Format a date with MomentJS, without local time adjustment - javascript

I want to display a unix timestamp (which is in UTC) as a formatted date.
I also want to keep it in the UTC timezone (so no change to the hours based on TZ). How can I do this?
Example:
moment(unix_timestamp).format('MMMM D, YYYY - H:mm:SS.SSSS') converts the output into the computer's local time.
Moment Docs:
Found this section in the docs, but none of the options seem to work:
https://momentjs.com/guides/#/parsing/local-utc-zone/

As far as documentation states:
Note that if you use moment() or moment.utc() to parse a date with a specified offset, the date will be converted from that offset to either local or UTC:
moment('2016-01-01T00:00:00+02:00').format() //converted to local
moment.utc('2016-01-01T00:00:00+02:00').format() //treated as UTC

Related

How to display times in different time zones using the offset value

I am trying to display the current moment in different time zones. I have tried to use native javascript and the moment-js package but it seems you require the time zone name (ex. "America/Toronto") to display the information I want. The problem is that the information I currently have is the timestamp in string format (see below for string format) from the desired timezone, and the city the timestamp belongs to. The problem with using the city to create my tz value is that one of the cities I want to display isn't in the IANA tz database (Calgary).
String timestamp:
2022-04-26T14:19:42.8430964-04:00
As can be seen I do have the time offset and I was hoping there was a way to convert this string in js to a Date object and then display the time using the offset in the correct time zone.
Note what I want to display is the following format:
12:19 pm MT
I know I could just parse out the string but I feel like this isn't the best practice, however I may be wrong.
Also note that I will have to get the time zone (ex. MT, ET it can also be MST, EST) using the offset.
you don't need moment here. JS can do this natively. Also moment is now deprecated.
Your IANA timezone is America/Edmonton. So it's simple to do. That date format is an ISO 8601 date format, so you can just pass it into the new Date constructor and it'll parse it correctly:
const iso8601 = '2022-04-26T14:19:42.8430964-04:00';
const date = new Date(iso8601);
console.log(date.toLocaleString('en-US', { timeZone: 'America/Edmonton' }));
It doesn't matter what timezone your input date is set, so long as it has the correct offset in the ISO date. Once it's a Date, the offset is irrelevant. E.g.:
const iso8601 = '2022-04-26T14:19:42.8430964Z';
const date = new Date(iso8601);
//time will now be 4 hours off above as the input date is UTC
console.log(date.toLocaleString('en-US', { timeZone: 'America/Edmonton' }));

How to obtain unix timestamps for same date in 2 different time zones with moment.js?

I'm working on an app where users can choose what time zone they are recording time in. But internally, I want to store the time as a unix timestamp.
Say I have a date '2016-01-01 1:00 pm'. If I store this date in CDT (America/Chicago), it is my understanding that the resulting unix time stamp should be different than had I stored the same date in MDT (America/Denver). However, I get the same unix time stamp for both dates, and I'm having trouble understanding why.
var chicagoDate = moment('2016-01-01 1:00 pm').tz('America/Chicago');
var denverDate = moment('2016-01-01 1:00 pm').tz('America/Denver');
chicagoDate.format();
// "2016-01-01T07:00:00-06:00"
denverDate.format();
// "2016-01-01T06:00:00-07:00"
So far this confirms that the 2 dates are distinct from one another as shown by their UTC representation obtained by using format(). But here is where I'm getting confused:
chicagoDate.unix();
// 1451653200
denverDate.unix();
// 1451653200
Shouldn't 2 distinct UTC dates result in 2 distinct unix timestamps?
In:
moment('2016-01-01 1:00 pm').tz('America/Chicago');
there is no parse format parameter, so moment.js looks to see if the format is one that it can parse without the format. It can't, so it falls back to the built–in parser as if you'd written:
moment(new Date('2016-01-01 1:00 pm')).tz('America/Chicago');
And puts warning in the console:
Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions…
Safari at least parses it as an invalid date (timestamp), so you should include the parse format:
moment(new Date('2016-01-01 1:00 pm', 'YYYY-MM-DD h:mm a')).tz('America/Chicago');
Secondly, the string is parsed as local since there is no timezone associated with the timestamp. So both lines of code produce exactly the same time value (i.e. offset from the epoch) and the two Dates produced are effectively identical.
The call to tz sets the timezone to use for all subsequent operations, so the output shows different times because different offsets have been applied at the formatting stage. The actual Dates being formatted are still effectively identical.
If you want the string to be parsed as for another timezone, you need to either manually include it in the string at the parse stage (e.g. '-06:00' or whatever), or use a library like Luxon with an IANA location (e.g. 'America/Chicago').

Converting a date, time and offset into an ISO8601 DateTime using moment.js and moment timezone

I am processing some itinerary data where the times and dates are all provided in the local timezone. I am adding this data to a database where I'd like to store all of the dates in UTC, with the proper timezone offset. I'm trying to process these dates with moment.js.
The input string for date/time is formatted like this 2020-07-12 13:00 and the timezone is in this format Europe/Amsterdam.
I want to end up with a string like:
2020-07-12T11:00:00+02:00
The trouble I'm having, is that moment converts my input time to either local time or utc if I use the .utc() method.
This code is getting me the correct result, but I don't understand why and I'm not sure if I can rely on its accuracy:
var offset = moment.tz(`Europe/Amsterdam`).utcOffset();
var m = moment(`2020-07-12 13:00`, 'YYYY-MM-DD HH:mm').utc().subtract(240 + offset + offset, 'minutes').utcOffset(offset); // (240 is my own UTC offset)
How can I simply input a date, time and timezone and end up with a correct ISO8601 DateTime?
If you are already using Moment and Moment-TimeZone in your app, then you can simply do the following:
const m = moment.tz('2020-07-12 13:00', 'YYYY-MM-DD HH:mm', 'Europe/Amsterdam');
m.format() //=> "2020-07-12T13:00:00+02:00"
However, the Moment team recommends using Luxon for new development. The equivalent is:
const dt = luxon.DateTime.fromFormat('2020-07-12 13:00', 'yyyy-MM-dd HH:mm', { zone: 'Europe/Amsterdam'});
dt.toISO() //=> "2020-07-12T13:00:00.000+02:00"
The only difference being that milliseconds are included. You can use a different formatting function if you prefer a different output.
The main benefit of Luxon is that it uses the built-in time zone functionality provided by the ECMAScript Internationalization API, whereas Moment-Timezone bundles its own time zone data - which can be quite large.
Also, note that in your question by asking for 2020-07-12T11:00:00+02:00 you seem to be misunderstanding the ISO 8601 format. In that format, the time presented is the local time. Thus, it should be 13:00, not 11:00. The +02:00 means, "this was the offset from UTC for this local time". (It doesn't mean that you apply the offset to get the local time.)

Given a date/time and timezone, how do you convert that into a UTC timestamp?

I am calling an API that returns a date/time string such as "2014-04-30 15:32:01". On top of this, I have a known timezone that this date/time exists in. I can see from the javascript Date() class has a .UTC() call for this, but that does not seem to accept a timezone as far as I can tell.
Given the date/time string + timezone, how can I convert those into a UTC timestamp?
I'd recommend using Moment.js and Moment Timezone.
You can create a timestamp using Date.parse from your local time (RFC2822 date format to include the timezone), create a date from that and use Date.toUTCString to get the UTC time. Not sure if it'll work with day light savings though.
Example: http://jsfiddle.net/3vXV6/ (will alert the date)
References:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString

Format date in a specific timezone

I'm using Moment.js to parse and format dates in my web app. As part of a JSON object, my backend server sends dates as a number of milliseconds from the UTC epoch (Unix offset).
Parsing dates in a specific timezone is easy -- just append the RFC 822 timezone identifier to the end of the string before parsing:
// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")
// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")
console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
But how do I format a date in a specifc timezone?
I want consistent results regardless of the browser's current time, but I don't want to display dates in UTC.
As pointed out in Manto's answer, .utcOffset() is the preferred method as of Moment 2.9.0. This function uses the real offset from UTC, not the reverse offset (e.g., -240 for New York during DST). Offset strings like "+0400" work the same as before:
// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')
The older .zone() as a setter was deprecated in Moment.js 2.9.0. It accepted a string containing a timezone identifier (e.g., "-0400" or "-04:00" for -4 hours) or a number representing minutes behind UTC (e.g., 240 for New York during DST).
// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')
To work with named timezones instead of numeric offsets, include Moment Timezone and use .tz() instead:
// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
A couple of answers already mention that moment-timezone is the way to go with named timezone. I just want to clarify something about this library that was pretty confusing to me. There is a difference between these two statements:
moment.tz(date, format, timezone)
moment(date, format).tz(timezone)
Assuming that a timezone is not specified in the date passed in:
The first code takes in the date and assumes the timezone is the one passed in.
The second one will take date, assume the timezone from the browser and then change the time and timezone according to the timezone passed in.
Example:
moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"
moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"
My timezone is +5 from utc. So in the first case it does not change and it sets the date and time to have utc timezone.
In the second case, it assumes the date passed in is in -5, then turns it into UTC, and that's why it spits out the date "2018-07-18T00:00:00Z"
NOTE: The format parameter is really important. If omitted moment might fall back to the Date class which can unpredictable behaviors
Assuming the timezone is specified in the date passed in:
In this case they both behave equally
Even though now I understand why it works that way, I thought this was a pretty confusing feature and worth explaining.
Use moment-timezone
moment(date).tz('Europe/Berlin').format(format)
Before being able to access a particular timezone, you will need to load it like so (or using alternative methods described here)
moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
.zone() has been deprecated, and you should use utcOffset instead:
// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
I was having the same issue with Moment.js. I've installed moment-timezone, but the issue wasn't resolved. Then, I did just what here it's exposed, set the timezone and it works like a charm:
moment(new Date({your_date})).zone("+08:00")
Thanks a lot!
Just came acreoss this, and since I had the same issue, I'd just post the results I came up with
when parsing, you could update the offset (ie I am parsing a data (1.1.2014) and I only want the date, 1st Jan 2014. On GMT+1 I'd get 31.12.2013. So I offset the value first.
moment(moment.utc('1.1.2014').format());
Well, came in handy for me to support across timezones
B
If you pass the timestamp as the parameter to moment() (e.g if the timezone is Asia/Hong_kong which is +08:00), what I do is:
const localDateTime = moment((item.createdAt.seconds + 8 * 3600) * 1000).format('YYYY-MM-DD HH:mm:ss');
You can Try this ,
Here you can get the date based on the Client Timezone (Browser).
moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')
The regex basically gets you the offset value.
Cheers!!

Categories