24

I'm pulling dates from a SQL database which treats them as dates that start at midnight. When I go to use toLocaleDateString() on them, it formats them properly, however not before losing a day.

Before formatting: 2011-09-01T00:00:00

After formatting: 8/31/2011

Code:

plan.dateReceived = new Date(plan.dateReceived).toLocaleDateString()+','+plan.dateReceived;

Why does it do this, and what inline fix can I make to have it behave properly? I also found another post that had a similar problem, but I'm not 100% convinced that it's a timezone issue.

Community
  • 1
  • 1
MarkDee
  • 307
  • 1
  • 2
  • 10
  • The technique described in that [other post](http://stackoverflow.com/questions/28344408/why-does-js-subtract-a-day-from-a-date-object-with-a-certain-format) that you linked to does actually work. It is precisely because it is a timezone issue, unfortunately. BTW, if the native JS Date behaviour is too limiting, try [MomentJS](http://momentjs.com/) instead. – GregL Sep 30 '15 at 23:57

3 Answers3

60

If you run the code in pieces, you'll notice that new Date('2011-09-01T00:00:00') produces output like Wed Aug 31 2011 20:00:00 GMT-0400 (EDT) (my computer is in EDT right now).

This is because (doc):

Differences in assumed time zone

Given a date string of "March 7, 2014", parse() assumes a local time zone, but given an ISO format such as "2014-03-07" it will assume a time zone of UTC. Therefore Date objects produced using those strings will represent different moments in time unless the system is set with a local time zone of UTC. This means that two date strings that appear equivalent may result in two different values depending on the format of the string that is being converted (this behavior is changed in ECMAScript ed 6 so that both will be treated as local).

Converting that to the locale date string will convert it to a string appropriate for the browser's locale. Documentation indicates that "the default is the runtime's default time zone".

If you want to ensure the string is in UTC time, use

new Date('2011-09-01T00:00:00').toLocaleDateString('en-US', {timeZone: 'UTC'})
arcyqwerty
  • 10,325
  • 4
  • 47
  • 84
1

We experienced this problem on Google Chrome v87.0.4280 IOS, but not on a computer with the same browser.

The problem was that the timezone string did not contain a Z at the end.

"Z" is kind of a unique case for DateTimes. The literal "Z" is actually part of the ISO 8601 datetime standard for UTC times. When "Z" (Zulu) is tacked on the end of a time, it indicates that that time is UTC, so really the literal Z is part of the time.

Appending Z to the datetime fixed the problem.

new Date('2011-09-01T00:00:00Z').toLocaleDateString('en-US', {timeZone: 'UTC'})
0

The answer above stating "This means that two date strings that appear equivalent may result in two different values depending on the format of the string that is being converted (this behavior is changed in ECMAScript ed 6 so that both will be treated as local).".

This may have been correct at the time of writing, but it looks like they changed their minds, as it no longer says that if you click through. Also from testing in Chrome 109 any ISO 8601 format date, is parsed as UTC NOT local. As it always was. Nothing has changed in ECMAScript ed 6 and above. The updated text is below. Hopefully that saves somebody some time.

Given a non-standard date string of "March 7, 2014", parse() assumes a local time zone, but given a simplification of the ISO 8601 calendar date extended format such as "2014-03-07", it will assume a time zone of UTC. Therefore Date objects produced using those strings may represent different moments in time depending on the version of ECMAScript supported unless the system is set with a local time zone of UTC. This means that two date strings that appear equivalent may result in two different values depending on the format of the string that is being converted.

jtym
  • 49
  • 4