4

I get dates from the database in this format:

yyyy-mm-dd

When I create a javascript Date object using this string, it builds a day before the date.

You can test this in your console:

var d = new Date("2015-02-01"); 
d

You will get January 31st! I've tested many theories, but none answer the question.

  • The day is not zero-based, otherwise it would give Feb 00, not Jan 31
  • It's not performing a math equation, subtracting the day from the month and/or year
    • Date(2015-02-01) = Wed Dec 31 1969
    • Date("2015-01") = Wed Dec 31 2014
  • It is not confusing the day for the month
    • Date("2015-08-02") = Sat Aug 01 2015
    • If this were true the date would be Feb 08 2015
  • If you create a Date using a different format, it works fine
    • Date("02/01/2015") = Feb 1st, 2015

My conclusion is that js does this purposefully. I have tried researching 'why' but can't find an explanation. Why does js build dates this way, but only with this format? Is there a way around it, or do I have to build the Date, then set it to the next day?

PS: "How to change the format of the date from the db" is not what I'm asking, and that is why I'm not putting any db info here.

Travis Heeter
  • 13,002
  • 13
  • 87
  • 129
  • I'm not sure but could this be a timezone issue? – Phil Feb 05 '15 at 13:05
  • 2
    Your last question and your PS contradict each other. I would just transform the database result to a support format and use that for the date. Do not add or remove days. As for why it does this... maybe this: 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. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse – Stephan Bijzitter Feb 05 '15 at 13:12
  • Chrome works fine. `new Date("2015-02-01");` --> `Sun Feb 01 2015 03:00:00 GMT+0300 (MSK)` – gorpacrate Feb 05 '15 at 13:25
  • @gorpacrate Not for me. new Date("2015-02-01) -> Sat Jan 31 2015. – Travis Heeter Feb 05 '15 at 13:44
  • 1
    Hah, fun. That one was on my mac. Just tried in chrome for windows - yes, it's Sat Jan 31 2015. – gorpacrate Feb 05 '15 at 14:04
  • @StephanBijzitter That seems to be the explanation: It assumes a timezone of UTC when using a UTC date string, and local time if the time is specified or in another format. If I add "T08:00:00" to the string, it creates the correct date: `new Date("2015-02-01T08:00:00")` -> `Sun Feb 01` Thanks! If you create an answer and leave out the stuff about changing the db format I'll give you credit. – Travis Heeter Feb 05 '15 at 14:06
  • @gorpacrate Woah. That is so weird. Does that mean that Mac Browsers use a different js than Windows? – Travis Heeter Feb 05 '15 at 14:08
  • I had different time zones on win and mac. GMT+3 on mac and GMT-8 on win. I've changed windows's timezone to my local GMT+3 and it returns now the correct date. Check your timezone settings.. – gorpacrate Feb 05 '15 at 14:19
  • @gorpacrate Oh, your times were different! Whew, my whole javascript world was crumbling around me for a second. If you check the comment from StephanBijzitter, you'll see that since the format "yyyy-mm-dd" is concidered "UTC format" it ignores your timezone and uses UTC time. However any other format creates a date based on your time. It seems like a really stupid pitfall in js, but the Date object has a lot of those I'm discovering. – Travis Heeter Feb 05 '15 at 14:23
  • Continued testing.. UTC time returns 1Feb, UTC-1 returns 31Jan. Anyway, it would be a good bulletproof practice to parse your string manually. new Date(2015, 1, 1) (dont forget that months start from 0 in js) returns correct value independently on system timezone settings. Good luck ;) – gorpacrate Feb 05 '15 at 14:27
  • Possible duplicate of [Is the Javascript date object always one day off?](https://stackoverflow.com/questions/7556591/is-the-javascript-date-object-always-one-day-off) – Heretic Monkey Apr 30 '19 at 19:59

2 Answers2

3

Some browsers parse a partial date string as UTC and some as a local time,

so when you read it the localized time may differ from one browser to another

by the time zone offset.

You can force the Date to be UTC and add the local offset if you

want the time to be guaranteed local:

1. set UTC time:    

var D= new Date("2015-02-01"+'T00:00:00Z');


2. adjust for local:

D.setMinutes(D.getMinutes()+D.getTimezoneOffset());

value of D: (local Date) Sun Feb 01 2015 00:00:00 GMT-0500 (Eastern Standard Time)

Offset will be whatever is local time.

Some differences between browsers when time zone is not specified in a parsed string:

(tested on Eastern Standard Time location)

(new Date("2015-02-01T00:00:00")).toUTCString();


Firefox 35: Sun, 01 Feb 2015 05:00:00 GMT

Chrome 40: Sun, 01 Feb 2015 00:00:00 GMT

Opera 27: Sun, 01 Feb 2015 00:00:00 GMT

IE 11: Sun, 01 Feb 2015 05:00:00 GMT

IE and Firefox set the Date as if it was local, Chrome and Opera as if it was UTC. 
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • I don't think browsers are being inconsistent here. If you don't give a time in an iso 8601 date string then 00:00:00 is assumed. If you don't give a timezone component in a iso 8601 date string, then UTC is assumed. Js just stores the date as number of miliseconds since Jan 1st 1970 00:00:00 UTC. The difference in console outputs is to do with the different OS timezones used when logging the dates back out again. That is when local timezone is used. – Phil Feb 05 '15 at 18:40
0

In javascript, Date objects are internally represented as the number of milliseconds since Jan 1st 1970 00:00:00 UTC. So instead of thinking of it as a "date" in the normal sense, try thinking of a Date object as a "point in time" represented by an integer number (without timezone).

When constructing your Date object using a string, you are actually just calling the parse function. Most date time formats (including ISO 8601) allow you to reduce the precision of a date string.

For reduced precision, any number of values may be dropped from any of the date and time representations, but in the order from the least to the most significant.

e.g. 2015-02-01 would represent the day February 1st 2015.

This causes a dilemma for javascript because a Date object is always accurate to the millisecond. Javascript cannot store a reduced accuracy date since it is just an integer of milliseconds since 1st Jan 1970. So it does the next best thing which is to assume a time of midnight (00:00:00) if not specified, and a timezone of UTC if not specified.

All valid javascript implementations should give the same result for this:

var d = new Date("2015-02-01");
alert(d.getTime());

1422748800000

The out-by-1-day issue comes when outputting the date either to some (often unclear) debugger or using the getter methods because the local timezone is used. In a browser, that will be your operating systems timezone. Anyone "west" of Greenwich Mean Time may see this problem because they have a negative UTC offset. Please note there are UTC equivalent functions too which use the UTC timezone, if you are really just interested in representing a date rather than a point in time.

Phil
  • 1,996
  • 1
  • 19
  • 26