moment.utc(string) parses ISO8601 as local time when timezone is missing

Created on 12 Apr 2012  ·  24Comments  ·  Source: moment/moment

Most helpful comment

I must add to the expression of confusion around the UTC functionality. The most intuitive expectation of moment.utc() would be that it would return a Moment object representing the now date/time in UTC time. But according to this discussion it's not the case and it just sets the flag. It still unclear what that flag does. None of this is mentioned in the documentation, which makes it woefully inadequate. Please add clarification of this topic with examples to your backlog. Thank you.

All 24 comments

moment.utc(string) parses ISO8601 as local time when timezone is missing

this is how ISO8601 says... and EcmaScript 6

I think that applies to moment(string) pretty well, but when using moment.utc(string), I think the implication is that you want it parsed as UTC.

moment('2010-10-20T08:40'); // should parse to local time
moment.utc('2010-10-20T08:40'); // should parse to utc time

I'm having an issue, I think related with this:

I'm trying to convert this date: 12-04-2012 (DD-MM-YYYY, in UTC) to its Unix timestamp.
I'm doing this:

var date = '12-04-2012';
var mm = moment().utc( date, "DD-MM-YYYY" );
console.log( mm.valueOf() );

This outputs an incorrect timestamp: 1334670827391.
If I try:

console.log( mm.format('DD-MM-YYYY') );

It outpus: 17-04-2012

a538306 fixes this. Will go out in 1.6.0

I'm still seeing this issue in the latest version..

I'm passing in: moment.utc('2012-12-14T00:29:40.276Z') and getting: {_d: Thu Dec 13 2012 18:29:40 GMT-0600 (Central Standard Time), _isUTC: true (Thu Dec 13 2012 18:29:40 GMT-0600 (Central Standard Time) ).. It's not using the utc time but my local timezone.

This is what I'm getting with 1.7.2.

moment.utc('2012-12-14T00:29:40.276Z').format(); // "2012-12-14T00:29:40+00:00"

Here is what happens for me (latest version) when I write to the console in chrome:

console.log(moment.utc('2012-12-14T00:29:40.276Z'));
console.log(moment.utc('2012-12-14T00:29:40.276Z').format());
console.log(moment.utc('2012-12-14T00:29:40.276Z').toDate());

H {_d: Thu Dec 13 2012 18:29:40 GMT-0600 (Central Standard Time), _isUTC: true, _a: Array[8], _lang: false, clone: function…}

2012-12-14T00:29:40+00:00

Thu Dec 13 2012 18:29:40 GMT-0600 (Central Standard Time)

Shouldn't it be creating a new date in utc (no time zone)? Also the first console.log shows the moment object with a cst timezone and not it's utc time.

Thu Dec 13 2012 18:29:40 GMT-0600 is actually the exact same time as 2012-12-14T00:29:40.276Z. They are just different ways of displaying the same time. If you want, you can see this by doing the following.

console.log(moment.utc('2012-12-14T00:29:40.276Z').toDate().toString());
// Thu Dec 13 2012 16:29:40 GMT-0800 (PST)
console.log(moment.utc('2012-12-14T00:29:40.276Z').toDate().toUTCString());
// Fri, 14 Dec 2012 00:29:40 GMT

The native JS Date does not have a utc vs local mode, it just has accessors like getUTCHours and getHours.

Moment.js abstracts these getUTC* vs get* methods with the idea of utc mode and local mode. If the moment is in utc mode, it uses the getUTC* methods. If it is in local mode, it uses the get* methods.

Thanks, for the clarification.

I was expecting and thought that sinze the iso standard states that Z means no timezone that it would default to utc. So if you did moment.utc('2012-12-14T00:29:40.276Z') or moment('2012-12-14T00:29:40.276Z'), both would be treated as utc and the utc flag would be set to true.

P.S., sorry for bothering you so much :. I'm creating a new discussion for a different question :s

No problem.

The reason we don't set the isUTC flag with both moment() and moment.utc() is because even though you may be parsing a UTC+0 string, you may want to display the moment in the users timezone.

This is a pretty common use case, as it's a good practice to store times as ISO8601 UTC+0 strings on the backend and display them on the frontend in the user's timezone.

Thanks, I hope someone else finds this discussion helpful too.

When I run console.log(moment.utc()), it reports "Fri Jan 18 2013 16:25:32 GMT-0800 (UTC)" However, that is local Pacific time, NOT the current UTC time. Since it explisitly says (UTC) when I log it, I assume that it thinks "16:25:32" is in UTC time, but it is indeed local pacific time...

Additionally, I am assuming moment.utc().valueOf() is returning the number of milliseconds in UTC since epoch, which appears to be incorrect. Have you seen any of this behavior?

console.log(moment())
H {_d: Fri Jan 18 2013 16:51:20 GMT-0800 (UTC), _isUTC: false, _a: null, _lang: false}
console.log(moment.utc())
H {_d: Fri Jan 18 2013 16:51:20 GMT-0800 (UTC), _isUTC: true, _a: null, _lang: false}

It would appear all that it is doing is flipping the _isUTC flag. :P It appears to be returning local time regardless of whether or not I specify .utc().

Yes, .utc and .local just flip the .isUTC flag which is used in all the getters and setters.

Because the native Date.toString is displayed in local time, you are seeing the same representation in both instances.

However, .format uses the .isUTC flag, so formatting a moment with the isUTC flag set to true will format as expected.

See the differences below regarding Date.prototype.toString, Date.prototype.toUTCString, and moment.fn.format.

moment().toDate().toString();     // "Wed Jan 23 2013 09:48:54 GMT-0800 (PST)"
moment.utc().toDate().toString(); // "Wed Jan 23 2013 09:48:54 GMT-0800 (PST)"
moment().toDate().toUTCString();     // "Wed, 23 Jan 2013 17:48:54 GMT"
moment.utc().toDate().toUTCString(); // "Wed, 23 Jan 2013 17:48:54 GMT"
moment().format();     // "2013-01-23T09:48:54-08:00"
moment.utc().format(); // "2013-01-23T17:48:54+00:00"

Same problem here:
moment().valueOf() and moment().utc().valueOf()
return the same value! :disappointed:

So to get the utc milliseconds I need to:

moment().valueOf() - (moment().utcOffset() * 60 * 1000)

@rubenspgcavalcante - I'm not sure what you're asking. Those two are _supposed_ to return the same value, both of which are in milliseconds since the unix epoch.

The snippet you wrote actually returns a different moment in time.

I'm having similar issue where the UTC flag is set to true but when I cal format(); It returns the local time. Here is a screenshot.

screen shot 2016-07-10 at 8 50 15 am

The line after the object is a console.log of the var after I call format(); on it.

Am I doing something wrong?

@james-hoegerl it looks like the internal date object is July 5 2016 at 19:00 central. Add five hours to that to get to UTC, and it is July 6, which is what appears to be logging, so in short, I don't see anything wrong.
It does look like you're using fullcalendar. It does some extension/monkey patching of moment that may cause unusual behavior.

Ok maybe I'm just confused about uct. I thought I would get "2016-05-07 07:00:00" then I could store that in the DB and then get local time for each end user computer via moment.

So, first of all I will assume you meant 6016-07-05 (July 5th, not May 7th). Your local time is July 5th at 19:00. Adjusted for US Central Daylight, we add five hours. That yields July 6th at midnight.

If you mean to get July 5th, then I think what you actually want is local time, not UTC. You could call .local() on the moment to get it back to local time.

You may find this helpful: https://maggiepint.com/2016/05/14/moment-js-shows-the-wrong-date/

Thanks very much for your help @maggiepint. Yes my previous comment I did mean 7-5. Sorry about that I wrote that comment hastily on my phone by the pool this weekend. I see where my thinking has been backwards now. fullcalendar works on all ambiguous time zoned moment objects so I think I was just having some misunderstanding there and need to do some sutdying on that. Thanks again for your time @maggiepint

Hi, To convert UTC to user time, do we need to provide format.
for example : let utcTime = moment({ hour : 10, minute : 20).format('YYYY-MM-DD HH:mm:ss');
let stillUtc = moment.utc(utcTime).toDate();
let localTime = moment(stillUtc).local();
Now i can able to get localTIme. But if i remove format i can still UTC format . here 10:20 is UTC timeZone which is coming from backend. I want to show this to user in user timezone.

Please help me.

Same problem here:
moment().valueOf() and moment().utc().valueOf()
return the same value! 😞
So to get the utc milliseconds I need to:
moment().valueOf() - (moment().utcOffset() * 60 * 1000)

@rubenspgcavalcante - I'm not sure what you're asking. Those two are supposed to return the same value, both of which are in milliseconds since the unix epoch.

@mj1856 I don't understand how moment().valueOf() and moment().utc().valueOf() are supposed to return the same value ??

I must add to the expression of confusion around the UTC functionality. The most intuitive expectation of moment.utc() would be that it would return a Moment object representing the now date/time in UTC time. But according to this discussion it's not the case and it just sets the flag. It still unclear what that flag does. None of this is mentioned in the documentation, which makes it woefully inadequate. Please add clarification of this topic with examples to your backlog. Thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Shoroh picture Shoroh  ·  3Comments

RobinvanderVliet picture RobinvanderVliet  ·  3Comments

vbullinger picture vbullinger  ·  3Comments

benhathaway picture benhathaway  ·  3Comments

dogukankotan picture dogukankotan  ·  3Comments