Reputation: 23
I have the following returned from an event,
"epochMilli": 1669288500000,
"timezoneOffsetInSeconds": -18000
I need to use this and convert it to a date to get day, month and year using JavaScript.
I wasn't able to find any function in JavaScript to do this. I found the same in Java:
OffsetDateTime offsetdatetime = Instant.ofEpochSecond(time).atOffset(ZoneOffset.ofTotalSeconds(offset));
LocalDate localdate = offsetDateTime.toLocalDate();
How to accomplish the same in JavaScript?
Upvotes: 1
Views: 511
Reputation: 46753
Assuming you want the year/month/day according to the time zone with the provided offset, you can do this fairly easily. The key is to only use the UTC*
methods of the Date
object, and to adjust the milliseconds by the offset before calling any of those methods. This is NOT clear code... it'd need to be exhaustively commented to explain to readers that it's not actually a UTC value being read, but rather you're abusing Date
to pretend it's a UTC value in order to read the date.
function getDateInOffsetTimeZone(epochMilli, offsetSeconds) {
const adjustedMilli = epochMilli + offsetSeconds * 1000;
const date = new Date(adjustedMilli);
return { year: date.getUTCFullYear(), month: date.getUTCMonth() + 1, day: date.getUTCDate() };
}
getDateInOffsetTimeZone(1669288500000, -18000);
// => { year: 2022, month: 11, day: 24 }
Or you could write this in Temporal, the improved, coming-soon date/time API for JavaScript, which provides a clearer way to get the date without manually calculating the offset and lying about using UTC.
import { Temporal } from '@js-temporal/polyfill';
function getDateInOffsetTimeZone(epochMilli, offsetSeconds) {
const instant = Temporal.Instant.fromEpochMilliseconds(epochMilli);
const offsetSign = offsetSeconds < 0 ? '-' : '+';
const offsetAsTime = new Temporal.PlainTime().add({ seconds: Math.abs(offsetSeconds) });
const offsetString = `${offsetSign}${offsetAsTime.toString()}`;
return instant.toZonedDateTimeISO(offsetString).toPlainDate();
}
getDateInOffsetTimeZone(1669288500000, -18000);
// => a Temporal.PlainDate object with { year: 2022, month: 11, day: 24 }
Note that the same UTC-abuse trick works in Temporal too, although as noted above I wouldn't recommend this because it's potentially confusing to readers.
function getDateInOffsetTimeZone(epochMilli, offsetSeconds) {
return Temporal.Instant.fromEpochMilliseconds(epochMilli)
.toZonedDateTimeISO('UTC')
.add({ seconds: offsetSeconds })
.toPlainDate();
}
getDateInOffsetTimeZone(1669288500000, -18000);
// => a Temporal.PlainDate object with { year: 2022, month: 11, day: 24 }
One thing to watch out for: the meaning of the sign of offsetSeconds
is ambiguous, depending on who is generating it. For example, I live in California, and during the winter the offset where I live is written as -08:00
. But new Date().getTimezoneOffset()/60
returns 8
. Neither is officially correct or incorrect; both represent a distance in hours from UTC, but the sign is reversed! So before using any of the code above, make sure you know which direction your input's sign points.
Thanks to @ptomato (who is one of my partners in crime in helping to design the Temporal API) for improving the code samples above and for pointing out the ambiguity of the sign of offsets.
Upvotes: 1
Reputation: 30715
i'd suggest using a library such as luxon
to do get the time in a different time zone.
You can create a FixedTimeZone
object to represent the zone in question, passing in the offset in minutes.
We can now create a DateTime in that zone, using DateTime.fromMillis
, and passing the zone object to the function.
The year, month, day values can be retrieved from their respective properties.
const { DateTime, FixedOffsetZone } = luxon;
const epochMilli = 1669288500000;
const timezoneOffsetInSeconds = -18000;
const zone = new FixedOffsetZone(timezoneOffsetInSeconds / 60)
const dt = DateTime.fromMillis(epochMilli, { zone });
console.log('Year:', dt.year);
console.log('Month:', dt.month);
console.log('Day:', dt.day);
console.log('Date (formatted):', dt.toFormat('yyyy-MM-dd HH:mm:ss'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/3.0.1/luxon.min.js" integrity="sha512-6ZJuab/UnRq1muTChgrVxJhSgygmL2GMLVmSJN7pcBEqJ1dWPbqN9CiZ6U3HrcApTIJsLnMgXYBYgtVkJ8fWiw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Upvotes: 0