Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

moment('YYYY-MM-DD') should be always set in UTC time zone. #1167

Closed
memolog opened this issue Oct 6, 2013 · 5 comments

Comments

@memolog
Copy link

@memolog memolog commented Oct 6, 2013

moment('2013-10-06').valueOf() and Date.parse('2013-10-06') do not result in the same time value if you are not in UTC time zone (I'm in Tokyo, +09:00).

A string like 'YYYY-MM-DD' (date only) is one of the valid ISO8601 format, so moment is expected to set it in UTC time zone, but actually moment seems to set it in local time zone.

The following example shows that you can see the different time value between moment and native Date.parse output if you are not in UTC time zone.

http://jsfiddle.net/zP7nv/3/

@icambron

This comment has been minimized.

Copy link
Member

@icambron icambron commented Oct 6, 2013

I don't know of anything in the spec specifying that date strings are expected to be in UTC. From Wikipedia's entry on ISO 8601:

If no UTC relation information is given with a time representation, the time is assumed to be in local time.

That doesn't actually say what time a date should be interpreted as (dates, as far as 8601 is concerned, are just dates, not a specific number of milliseconds), but given that we are translating a date to a time, it seems reasonable to follow the time rules, where everything is local unless specified otherwise. So I believe the behavior you see is correct. @mj1856, can you confirm? I don't have a copy of the spec and I'm certainly no expert on it.

If you want to explicitly specify UTC, use moment.utc():

moment.utc('2013-10-06').format(); //=> "2013-10-06T00:00:00+00:00"

Alternatively, can also use 'Z' the input string to make it parse it as a UTC time, like moment('2013-10-06Z'). I'm not sure if that's spec or not, but it's consistent with the spec's rule about 'Z' meaning UTC on times (e.g. moment('2013-10-06T12:30Z')). Note that until you specify otherwise, the moment will still express that parsed-as-UTC time as the equivalent local time:

var m = moment('2013-10-06Z');
m.format(); // => "2013-10-05T20:00:00-04:00"
m.utc().format(); //=> "2013-10-06T00:00:00+00:00"

Finally, you can of course pass the Date into moment():

moment(Date.parse('2013-10-06')).format(); //=> "2013-10-05T20:00:00-04:00"

I hope that helps!

@memolog

This comment has been minimized.

Copy link
Author

@memolog memolog commented Oct 6, 2013

Hmm, This topic seems to be more complicated than I expected.

ECMA-262 says the following at 15.9.1.15 [http://www.ecma-international.org/publications/standards/Ecma-262.htm]

All numbers must be base 10. If the MM or DD fields are absent 01 is used as the value. If the HH, mm, or ss fields are absent 00 is used as the value and the value of an absent sss field is 000. The value of an absent time zone offset is Z.

I guess a date-only string without time zone follow this rule, and some modern browsers (Chrome, Firefox) look doing so. (although I'm also not sure what is the right spec..)

Your alternatives looks great :)

thanks!

@icambron icambron closed this Oct 6, 2013
@mj1856

This comment has been minimized.

Copy link
Member

@mj1856 mj1856 commented Oct 6, 2013

There is a bit of a mismatch because ISO8601 implies that any time that doesn't have a Z or an offset like -04:00 is to be treated as local time. While ECMA-262 (ES5) says that it should be treated as UTC if absent.

In reality, browsers that support the ISO format tend to follow the ES5 rule when provided an input in YYYY-MM-DD format, as long as the separator is a hyphen (-). But if the separator is a slash (/), then they usually treat that as local time. However, I don't think it would be a good idea to have moment follow this convention.

One of the primary reasons for using moment (IMHO) is to have uniformity in parsing. Browser specifics and ES5 specs are not something we should aim for feature parity with. Moment is more than just a shim. One could argue that ES5 is "doing it wrong", and that moment implements ISO8601 more precisely. Although ES5 does make it clear that theirs is a "based upon a simplification of the ISO 8601 Extended Format", so it doesn't have to precisely implement it.

Regarding moment's way of allowing the YYYY-MM-DDZ input, ISO8601 doesn't specifically highlight that, but it doesn't prohibit it either. I think it's ok as long as it's understood that in Date or moment types, a date without a time is understood to be the same as the date at midnight (00:00). From a pure ISO8601 perspective, those are two different things, but that doesn't apply here because we don't yet have types for a date without a time in JavaScript. (I'm working on it... 😉 )

In general, I'd say moment's implementation is about as good as it's going to get.

@icambron

This comment has been minimized.

Copy link
Member

@icambron icambron commented Oct 6, 2013

Thanks for the clarifications.

I was just wondering that the other day: "I wonder if Matt's precise date library will support dates as dates and not as times at midnight?" Would clear up some of the ISO-vs-browser differences here and would help with other issues like midnight DSTs.

@mj1856

This comment has been minimized.

Copy link
Member

@mj1856 mj1856 commented Oct 6, 2013

It sure will. I'm modeling much of it off of the Noda Time core types, so it would be called a LocalDate. This also aligns mostly with JSR310 (new date/time api for Java 8). See this chart for an idea of the different types. I'll be doing many of these.

Just need more time in my day. Too busy with other things to gain momentum on this presently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.