8

I just found that if I use new Date('2015-1-1'), the time is no timezone effect, but If I use new Date('2015-01-01') the time has timezone effect in Node.js.

I output 4 Date():

    console.log(new Date('2015-1-1'));
    console.log(new Date('2015-01-1'));
    console.log(new Date('2015-1-01'));
    console.log(new Date('2015-01-01'));

the output is

Thu Jan 01 2015 00:00:00 GMT+0800 (CST)
Thu Jan 01 2015 00:00:00 GMT+0800 (CST)
Thu Jan 01 2015 00:00:00 GMT+0800 (CST)
Thu Jan 01 2015 08:00:00 GMT+0800 (CST)

you can see the last time is 08:00:00 because I'm in +8 timezone.

I think the output depends on the digit of the month or date number. When it's 10, 11 or 12 the output is always 08:00:00

I'm wondering why and if there is a better way to handle this except manually check the bit of month and date number?

Brick Yang
  • 5,388
  • 8
  • 34
  • 45
  • 1
    I get the same output when I run your examples on Chrome Javascript console so it appears to be a V8 bug/feature. – HBP Nov 29 '15 at 11:25
  • In Firefox I'm getting an invalid date for all but the last line. Also, I've found this from MDN: [Differences in assumed time zone](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Differences_in_assumed_time_zone) – Kobi Nov 29 '15 at 11:37
  • 5
    Yet another issue with parsing date strings. The **only** reliable way to parse a date string is to do it manually (though a library may help with that). The first 3 strings are not exactly ISO 8601 strings so can be parsed however the implementation wants. The last is an ISO 8601 format. Per ECMAScript 2015 it is parsed as "local" to the host system. Under ES5 it must be parsed as UTC, and before that (i.e. ECMAScript ed 3 and earlier) anything, including NaN. – RobG Nov 29 '15 at 11:41
  • @RobG you should post it as an answer. :) – Enrichman Nov 29 '15 at 11:57

2 Answers2

1

Up to and including ECMA-262 ed 3, parsing of date strings was entirely implementation dependent. With ES5, ISO 8601 format strings without a timezone were to be parsed as UTC, however parsing any other type of date string is still implementation dependent.

With ECMAScript 2015, such strings without a timezone are to be parsed as local (i.e. with an offset based on system settings).

So it would seem that your Node.js implementation does not recognise the first 3 strings as ISO 8601 and so parses them according to some other internal logic that treats them as UTC.

The last string is seen as ISO 8601 compliant and so is parsed as local.

If you wish to parse all such strings as local, you can use a simple function like:

/*  @param {string} s - date string in format yyyy-[m]m-[d]d
**  @returns {Date} - a Date object for the specified date in a
**  timezone based on system settings.
**  Assumes that the string is a valid date.
*/
function parseISOLocal (s) {
  var b = s.split(/\D/);
  return new Date(b[0], b[1]-1, b[2]);
}

document.write(parseISOLocal('2015-1-1'))
RobG
  • 142,382
  • 31
  • 172
  • 209
  • With this function I got `Thu Jan 01 2015 00:00:00 GMT+0800 (CST)`, no timezone offset, but the default `Date('2015-01-01') has timezone offset. – Brick Yang Nov 29 '15 at 12:06
  • @BrickYang—that first one does have a timezone offset (+08:00). – RobG Nov 30 '15 at 02:50
0

Probably a bug, the best that you can do is to use a library like Moment that seems free from this:

moment('2015-1-1').toString()
moment('2015-1-01').toString()
moment('2015-01-1').toString()
moment('2015-01-01').toString()

prints:

"Thu Jan 01 2015 00:00:00 GMT+0100"
"Thu Jan 01 2015 00:00:00 GMT+0100"
"Thu Jan 01 2015 00:00:00 GMT+0100"
"Thu Jan 01 2015 00:00:00 GMT+0100"
Enrichman
  • 11,157
  • 11
  • 67
  • 101
  • Not really, it just happens that moment.js, by default, has a certain behaviour. You haven't explained why the OP gets the result they get. – RobG Nov 29 '15 at 11:37
  • No idea why, my answer was referring to the "better way to handle this". Since Moment seems consistent on this and it also provides a lot of nice features seems a good way to handle this. – Enrichman Nov 29 '15 at 11:40
  • 1
    Moment will only be consistent if you tell it the format you're passing, otherwise it tries a series of possible formats and returns a date for the first one that it successfully parses. It can't, for example, tell if 3/2/105 is 3 February or 2 March. But with ISO-like formats it will probably be reliable (but so can a 2 line function to do the same thing). ;-) – RobG Nov 29 '15 at 11:44
  • Well, I guess that's a problem with all the date formats (and that's why you should always use a datepicker or date selector for this kind of user interactions). But as you said this seems to be an ISO-like format, and so yyyy-MM-dd (more or less) will be fine I guess. – Enrichman Nov 29 '15 at 11:49