[javascript] Is the Javascript date object always one day off?

In my Java Script app I have the date stored in a format like so:

2011-09-24

Now when I try using the above value to create a new Date object (so I can retrieve the date in a different format), the date always comes back one day off. See below:

var doo = new Date("2011-09-24");
console.log(doo);

logs:

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)

This question is related to javascript date

The answer is


The following worked for me -

    var doo = new Date("2011-09-24").format("m/d/yyyy");

I encountered this exact problem where my client was on Atlantic Standard Time. The date value the client retrieved was "2018-11-23" and when the code passed it into new Date("2018-11-23") the output for the client was for the previous day. I created a utility function as shown in the snippet that normalized the date, giving the client the expected date.

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

_x000D_
_x000D_
var normalizeDate = function(date) {_x000D_
  date.setMinutes(date.getMinutes() + date.getTimezoneOffset());_x000D_
  return date;_x000D_
};_x000D_
_x000D_
var date = new Date("2018-11-23");_x000D_
_x000D_
document.getElementById("default").textContent = date;_x000D_
document.getElementById("normalized").textContent = normalizeDate(date);
_x000D_
<h2>Calling new Date("2018-11-23")</h2>_x000D_
<div>_x000D_
  <label><b>Default</b> : </label>_x000D_
  <span id="default"></span>_x000D_
</div>_x000D_
<hr>_x000D_
<div>_x000D_
  <label><b>Normalized</b> : </label>_x000D_
  <span id="normalized"></span>_x000D_
</div>
_x000D_
_x000D_
_x000D_


Your log outputs GMT so you want to specify your timezone:

var doo = new Date("2011-09-24 EST");

Storing yyyy-mm-dd in MySql Date format you must do the following:

const newDate = new Date( yourDate.getTime() + Math.abs(yourDate.getTimezoneOffset()*60000) );
console.log(newDate.toJSON().slice(0, 10)); // yyyy-mm-dd

Trying to add my 2 cents to this thread (elaborating on @paul-wintz answer).

Seems to me that when Date constructor receives a string that matches first part of ISO 8601 format (date part) it does a precise date conversion in UTC time zone with 0 time. When that date is converted to local time a date shift may occur if midnight UTC is an earlier date in local time zone.

new Date('2020-05-07')
Wed May 06 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

If the date string is in any other "looser" format (uses "/" or date/month is not padded with zero) it creates the date in local time zone, thus no date shifting issue.

new Date('2020/05/07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-05-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

So then one quick fix, as mentioned above, is to replace "-" with "/" in your ISO formatted Date only string.

new Date('2020-05-07'.replace('-','/'))
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

This probably is not a good answer, but i just want to share my experience with this issue.

My app is globally use utc date with the format 'YYYY-MM-DD', while the datepicker plugin i use only accept js date, it's hard for me to consider both utc and js. So when i want to pass a 'YYYY-MM-DD' formatted date to my datepicker, i first convert it to 'MM/DD/YYYY' format using moment.js or whatever you like, and the date shows on datepicker is now correct. For your example

var d = new Date('2011-09-24'); // d will be 'Fri Sep 23 2011 20:00:00 GMT-0400 (EDT)' for my lacale
var d1 = new Date('09/24/2011'); // d1 will be 'Sat Sep 24 2011 00:00:00 GMT-0400 (EDT)' for my lacale

Apparently d1 is what i want. Hope this would be helpful for some people.


You are using the ISO date string format which, according to this page, causes the date to be constructed using the UTC timezone:

Note: parsing of date strings with the Date constructor (and Date.parse, they are equivalent) is strongly discouraged due to browser differences and inconsistencies. Support for RFC 2822 format strings is by convention only. Support for ISO 8601 formats differs in that date-only strings (e.g. "1970-01-01") are treated as UTC, not local.

If you format the text differently, such as "Jan 01 1970", then (at least on my machine) it uses your local timezone.


if you need a simple solution for this see:

new Date('1993-01-20'.split('-')); 

enter image description here


I believe that it has to do with time-zone adjustment. The date you've created is in GMT and the default time is midnight, but your timezone is EDT, so it subtracts 4 hours. Try this to verify:

var doo = new Date("2011-09-25 EDT");

Just want to add that apparently adding a space at the end of the string will use UTC for creation.

new Date("2016-07-06")
> Tue Jul 05 2016 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2016-07-06 ")
> Wed Jul 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

Edit: This is not a recommended solution, just an alternative answer. Please do not use this approach since it is very unclear what is happening. There are a number of ways someone could refactor this accidentally causing a bug.


nevermind, didn't notice the GMT -0400, wich causes the date to be yesterday

You could try to set a default "time" to be 12:00:00


This through me for a loop, +1 on zzzBov's answer. Here is a full conversion of a date that worked for me using the UTC methods:

//myMeeting.MeetingDate = '2015-01-30T00:00:00'

var myDate = new Date(myMeeting.MeetingDate);
//convert to JavaScript date format
//returns date of 'Thu Jan 29 2015 19:00:00 GMT-0500 (Eastern Standard Time)' <-- One Day Off!

myDate = new Date(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate());
//returns date of 'Fri Jan 30 2015 00:00:00 GMT-0500 (Eastern Standard Time)' <-- Correct Date!

You can convert this date to UTC date by

new Date(Date.UTC(Year, Month, Day, Hour, Minute, Second))

And it is always recommended to use UTC (universal time zone) date instead of Date with local time, as by default dates are stored in Database with UTC. So, it is good practice to use and interpret dates in UTC format throughout entire project. For example,

Date.getUTCYear(), getUTCMonth(), getUTCDay(), getUTCHours()

So, using UTC dates solves all the problem related to timezone issues.


There are several crazy things that happen with a JS DATE object that convert strings, for example consider the following date you provided

Note: The following examples may or may not be ONE DAY OFF depending on YOUR timezone and current time.

new Date("2011-09-24"); // Year-Month-Day
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

However, if we rearrange the string format to Month-Day-Year...

new Date("09-24-2011");
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Another strange one

new Date("2011-09-24");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF AS BEFORE.

new Date("2011/09/24"); // change from "-" to "/".
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

We could easily change hyphens in your date "2011-09-24" when making a new date

new Date("2011-09-24".replace(/-/g, '\/')); // => "2011/09/24".
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

What if we had a date string like "2011-09-24T00:00:00"

new Date("2011-09-24T00:00:00");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Now change hyphen to forward slash as before; what happens?

new Date("2011/09/24T00:00:00");
// => Invalid Date.

I typically have to manage the date format 2011-09-24T00:00:00 so this is what I do.

new Date("2011-09-24T00:00:00".replace(/-/g, '\/').replace(/T.+/, ''));
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

UPDATE

If you provide separate arguments to the Date constructor you can get other useful outputs as described below

Note: arguments can be of type Number or String. I'll show examples with mixed values.

Get the first month and day of a given year

new Date(2011, 0); // Normal behavior as months in this case are zero based.
// => Sat Jan 01 2011 00:00:00 GMT-0700 (MST)

Get the last month and day of a year

new Date((2011 + 1), 0, 0); // The second zero roles back one day into the previous month's last day.
// => Sat Dec 31 2011 00:00:00 GMT-0700 (MST)

Example of Number, String arguments. Note the month is March because zero based months again.

new Date(2011, "02"); 
// => Tue Mar 01 2011 00:00:00 GMT-0700 (MST)

If we do the same thing but with a day of zero, we get something different.

new Date(2011, "02", 0); // Again the zero roles back from March to the last day of February.
// => Mon Feb 28 2011 00:00:00 GMT-0700 (MST)

Adding a day of zero to any year and month argument will get the last day of the previous month. If you continue with negative numbers you can continue rolling back another day

new Date(2011, "02", -1);
// => Sun Feb 27 2011 00:00:00 GMT-0700 (MST)

I faced some issue like this. But my issue was the off set while getting date from database.

this is stroed in the database and it is in the UTC format.

2019-03-29 19:00:00.0000000 +00:00

So when i get from database and check date it is adding offset with it and send back to javascript.

enter image description here

It is adding +05:00 because this is my server timezone. My client is on different time zone +07:00.

2019-03-28T19:00:00+05:00 // this is what i get in javascript.

So here is my solution what i do with this issue.

var dates = price.deliveryDate.split(/-|T|:/);
var expDate = new Date(dates[0], dates[1] - 1, dates[2], dates[3], dates[4]);
var expirationDate = new Date(expDate);

So when date come from the server and have server offset so i split date and remove server offset and then convert to date. It resolves my issue.


If you want to get hour 0 of some date in the local time zone, pass the individual date parts to the Date constructor.

new Date(2011,08,24); // month value is 0 based, others are 1 based.

It means 2011-09-24 00:00:00 GMT, and since you're at GMT -4, it will be 20:00 the previous day.

Personally, I get 2011-09-24 02:00:00, because I'm living at GMT +2.


To normalize the date and eliminate the unwanted offset (tested here : https://jsfiddle.net/7xp1xL5m/ ):

var doo = new Date("2011-09-24");
console.log(  new Date( doo.getTime() + Math.abs(doo.getTimezoneOffset()*60000) )  );
// Output: Sat Sep 24 2011 00:00:00 GMT-0400 (Eastern Daylight Time)

This also accomplishes the same and credit to @tpartee (tested here : https://jsfiddle.net/7xp1xL5m/1/ ):

var doo = new Date("2011-09-24");
console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 )  );

Your issue is specifically with time zone. Note part GMT-0400 - that is you're 4 hours behind GMT. If you add 4 hours to the displayed date/time, you'll get exactly midnight 2011/09/24. Use toUTCString() method instead to get GMT string:

var doo = new Date("2011-09-24");
console.log(doo.toUTCString());

if you're just looking to make sure the individual parts of the date stay the same for display purposes, *this appears to work, even when I change my timezone:

var doo = new Date("2011-09-24 00:00:00")

just add the zeros in there.

In my code I do this:

let dateForDisplayToUser = 
  new Date( `${YYYYMMDDdateStringSeparatedByHyphensFromAPI} 00:00:00` )
  .toLocaleDateString( 
    'en-GB', 
    { day: 'numeric', month: 'short', year: 'numeric' }
  )

And I switch around my timezone on my computer and the date stays the same as the yyyy-mm-dd date string I get from the API.

But am I missing something/is this a bad idea ?

*at least in chrome. This Doesn't work in Safari ! as of this writing


Though in the OP's case the timezone is EDT, there's not guarantee the user executing your script will be int he EDT timezone, so hardcoding the offset won't necessarily work. The solution I found splits the date string and uses the separate values in the Date constructor.

var dateString = "2011-09-24";
var dateParts = dateString.split("-");
var date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);

Note that you have to account for another piece of JS weirdness: the month is zero-based.


The best way to handle this without using more conversion methods,

 var mydate='2016,3,3';
 var utcDate = Date.parse(mydate);
 console.log(" You're getting back are 20.  20h + 4h = 24h :: "+utcDate);

Now just add GMT in your date or you can append it.

 var  mydateNew='2016,3,3'+ 'GMT';
 var utcDateNew = Date.parse(mydateNew);
 console.log("the right time that you want:"+utcDateNew)

Live: https://jsfiddle.net/gajender/2kop9vrk/1/