This question already has answers here:
Why does Date.parse give incorrect results?
(11 answers)
Closed 2 years ago.
Came across this one tonight and thought I would throw it out there to see if anybody had a rational and clear explanation on what's going on.
I've declared two JavaScript date objects and passed in date strings to the constructor (same date).
In the first variable I have been explicit with the time and added 00:00.
In the second variable I have omitted the time (assuming that it would be midnight).
I've wrapped everything in a Self-Invoking Function but this has no bearing on the outcome.
I'm in GMT so I've used a date that is in BST (GMT+1).
(function() {
'use strict';
let a = new Date("2020-06-05 00:00");
let b = new Date("2020-06-05");
console.log(a);
console.log(b);
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
})();
I would have expected Fri Jun 05 2020 00:00:00 GMT+0100 (British Summer Time) on both cases but the second variable without the explicit 00:00 has been set to Fri Jun 05 2020 01:00:00 GMT+0100.
Any explanations?
It appears that a date inside BST (+1) without a time assumes it's +1.
Scenario doesn't happen with new Date("2020-01-05"); for example. This is outside BST and therefore +0.
Fri Jun 05 2020 00:00:00 GMT+0100 (British Summer Time)
Fri Jun 05 2020 01:00:00 GMT+0100 (British Summer Time)
"2020-06-04T23:00:00.000Z"
"2020-06-05T00:00:00.000Z"
Due to the ECMA specs:
ECMA-262 Date(value) constructor specs
Date.parse
If the String conforms to the Date Time String Format, substitute values take the place of absent format elements. When the MM or DD elements are absent, "01" is used. When the HH, mm, or ss elements are absent, "00" is used. When the sss element is absent, "000" is used. When the UTC offset representation is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time.
According to ECMA specs:
Date only forms without timezone are interpreted as UTC.
Date-Time without timezone are interpreted as local time.
Generally you are better off just using the full ISO-like form with timezone attached. But since these are spec-compliant, if you always keep it under control it's safe to depend on this behavior, albeit it might get confusing sometimes for both you and others, especially when it comes to server-side code and DB storage.
Related
This question already has answers here:
Why does Date.parse give incorrect results?
(11 answers)
Closed 6 years ago.
I feel like I am missing something here.
The Date.getDay() method is supposed to return a value from 0-6. 0 for Sunday and 6 for Saturday.
Now I have two dates, both are 'Sunday' which should return 0.
new Date('1990-11-11').getDay() // returns 6
new Date('2016-1-3').getDay() // returns 0
What is causing the discrepancy? I dare to question the validity of the .getDay() method, but I can't figure out what is going on.
EDIT
> new Date('1990-11-11')
Sat Nov 10 1990 17:00:00 GMT-0700 (MST)
> new Date('2016-01-03')
Sat Jan 02 2016 17:00:00 GMT-0700 (MST)
> new Date('2016-1-3') // they say this format is wrong, but it returns the right date
Sun Jan 03 2016 00:00:00 GMT-0700 (MST)
I don't understand what is going on. January 3rd is Sunday and November 11th 1990 is Sunday. Why is it saying Saturday?
The one that is wrong is the one that returns Sunday, and that must be because the format is incorrect. 1990-11-11 is interpreted as 00:00:00 on midnight of the 11th, UTC, which is 5pm on Saturday the 10th in your time zone.
If you use getUTCDay(), you should get 0 for both dates.
new Date('1990-11-11').getUTCDay() // returns 0
new Date('2016-01-03').getUTCDay() // returns 0
Certainly, your claim that 1990-11-11 is Sunday is true but you have to understand that JavaScript Date object:
Handles time as well as date
Is time zone aware
Is poorly designed and rather counter-intuitive
Your own tests illustrate this:
new Date('1990-11-11').getDay() // returns 6
> new Date('1990-11-11')
Sat Nov 10 1990 17:00:00 GMT-0700 (MST)
What happens is that constructor assumes local time or UTC depending on the syntax used:
Note: Where Date is called as a constructor with more than one
argument, the specifed arguments represent local time. If UTC is
desired, use new Date(Date.UTC(...)) with the same arguments.
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.
... and your syntax makes it as UTC. But many others methods assume local time:
The getDay() method returns the day of the week for the specified date
according to local time, where 0 represents Sunday.
getDay returns day index (from 0 to 6), where 0 is Sunday.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay
Return value:
An integer number corresponding to the day of the week for the given date, according to local time: 0 for Sunday, 1 for Monday, 2 for Tuesday, and so on.
Update:
new Date constructor returns different time values for those dates.
new Date('2016-1-3')
==> Sun Jan 03 2016 00:00:00 GMT+0100 (CET)
new Date('1990-11-11')
==> Sun Nov 11 1990 01:00:00 GMT+0100 (CET)
And for some reason, the first one gets interpreted as Saturday on your machine.
Sorry for not being able to help out more
Update2:
Using two digits for month/day should standardize the results.
Example:
(new Date('2016-01-03')).getDay() ==> 0
Why do I get 2 different dates with new Date() when I pass a date vs. when I pass a date and time?
example:
Date.parse('2015-03-14')
// 1426291200000
new Date(1426291200000)
// Fri Mar 13 2015 17:00:00 GMT-0700 (PDT)
Date.parse('2015-03-14 00:00:00')
// 1426316400000
new Date(1426291400000)
// Fri Mar 13 2015 17:03:20 GMT-0700 (PDT)
Sorry but I cannot comment yet. The string you pass in Date.parse() must follow the
ECMAScript 5 ISO-8601 format support
.Reference link here
format specified in ECMAScript 2015
According to that, you the format of Date with time must be: '2015-03-14T00:00:00' instead of '2015-03-14 00:00:00'.
And since the time of Date.parse('2015-03-14') is at GMT+00 but Date.parse('2015-03-14T00:00:00') is at your time zone so if you add timezone GMT+00 to the second two time will be equal:
Date.parse('2015-03-14');
Date.parse('2015-03-14T00:00:00+00:00');
//1426291200000
Why do I get 2 different dates with new Date() when I pass a date vs. when I pass a date and time?
Because parsing strings with the Date constructor (and Date.parse, they are equivalent) is largely implementation dependent and therefore strongly recommended against.
Date.parse('2015-03-14')
// 1426291200000
new Date(1426291200000)
// Fri Mar 13 2015 17:00:00 GMT-0700 (PDT)
ISO 8601 format dates are treated as UTC in browsers compliant with ES5 and later (and UTC, local or invalid by earlier implementations), however not all browsers are compliant. Also, the specified behaviour is inconsistent with ISO 8601, which specifies that dates without a time zone are to be treated as local.
Date.parse('2015-03-14 00:00:00')
// 1426316400000
new Date(1426291400000)
// Fri Mar 13 2015 17:03:20 GMT-0700 (PDT)
The string '2015-03-14 00:00:00' is not compliant with ISO 8601, therefore parsing is entirely implementation dependent and may be treated as UTC, local or invalid. If made compliant with the addition of a "T":
"2015-03-14T00:00:00"
it should be treated as local (noting the previously mentioned caveat about non–compliant implementations).
It is very strongly recommended that you always manually parse strings. Use a library, one of the many good parsers that are around or just write your own function, 2 or 3 lines should suffice.
This question already has an answer here:
HTML Input type datetime-local setting the wrong time-zone
(1 answer)
Closed 7 years ago.
I'm writing a MVC 5 web application. Into this, I have multiple lists that I propagate and manage through javascript and jquery (one dataset, dependent select controls, and adding ajax callbacks would complicate it unnecessarily.)
The issue I have is: I have a hidden for field formatted to ISO 8601. I run into issues when I display the date in the user's local time, I get a shifted date.
So if the date were stated as: 01-01-2009 (in iso 8601 format: 2009-01-01), the user sees: 12-31-2008.
When I parse the date I'm using:
this.date = new Date(Date.parse(originalString));
/* ^- Date.parse is giving me a number. */
To display the text of the date I am using:
admin.date.toLocaleDateString().Concat(...
Do I need to do any sort of patch-up to adjust things to the proper time-zone? The date, when using console.log(admin.date); shows the original 2009-01-01
I'm thinking there's some parameter I'm not specifying correctly in the toLocaleDateString, but my familiarity level with it is low.
Edit: The goal is to prevent the date shift. All we store is the date, the time aspect is dropped. We have multiple time-zones posting to this database, and the goal is: We use the date of the person who posted it, time dropped. Were the date May 01, 2015, I want anyone who sees that date to see May 01, 2015, the 'toLocaleDateString' is merely a means to get it to appear format correct for their region. So someone who views dates as yyyy-mm-dd will see it properly.
Based on the documentation for Date.parse:
The Date.parse() method parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC.
You are getting back the epoch time in UTC for your parsed date string hence why the date is off for local times. So, you would need to know the time difference between the local time and UTC which Date.getTimezoneOffset provides (in minutes) in order to set the correct date for the local time:
> var date = new Date(Date.parse('2009-01-01'));
undefined
> date;
Wed Dec 31 2008 19:00:00 GMT-0500 (EST)
> date.getTimezoneOffset();
300
> date.setMinutes(date.getTimezoneOffset());
1230786000000
> date;
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)
One thing to note though is:
...the offset is positive if the local timezone is behind UTC and negative if it is ahead.
So you might need to take care for locales where the value is negative if this applies to your application. If so maybe just omitting negative values would be enough since the date should be the same if a locale's timezone is ahead of midnight UTC.
EDIT: To compensate for possible issues with daylight savings time:
> var dateVals = String.prototype.split.call('2009-01-01', '-');
undefined
> var date = new Date(dateVals[0], dateVals[1] - 1, dateVals[2]);
undefined
> date
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)
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.
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.
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.
What's going on here:
> new Date('Apr 15 2013');
Mon Apr 15 2013 00:00:00 GMT+0100 (GMT Daylight Time)
> new Date('04/15/2013');
Mon Apr 15 2013 00:00:00 GMT+0100 (GMT Daylight Time)
> new Date('2013-04-15');
Mon Apr 15 2013 01:00:00 GMT+0100 (GMT Daylight Time)
Obviously, one is being interpreted as UTC time, while the other two are being interpreted as local time. What causes the difference in parsing?
From the specification:
The String may be interpreted as a local time, a UTC time, or a time in some other time zone, depending on the contents of the String. The function first attempts to parse the format of the String according to the rules called out in Date Time String Format (15.9.1.15). If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
Of all the formats you provided, only '2013-04-15' is officially supported, so the others seem to fall back to implementation-dependent behavior.
Your third example is the only one that is actually explained by the spec. When you call the Date constructor with a single argument, this is what happens (where v is the string passed to the constructor):
Parse v as a date, in exactly the same manner as for the parse method (15.9.4.2); let V be the time value for this date.
The parse method will attempt to parse the string (emphasis added):
The String may be interpreted as a local time, a UTC time, or a time in some other time zone, depending on the contents of the String. The function first attempts to parse the format of the String according to the rules called out in Date Time String Format (15.9.1.15).
If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
And the "Date Time String Format" is YYYY-MM-DDTHH:mm:ss.sssZ, and also defines a shorter version of the form YYYY-MM-DD, which is what you use in your third example.
For the other examples, the parse will fail and the behaviour is implementation-defined.
The Date constructor delegates to Date.parse, and it appears that Date.parse has two variants:
Given a string representing a time, parse returns the time value. It
accepts the RFC2822 / IETF date syntax (RFC2822 Section 3.3), e.g.
"Mon, 25 Dec 1995 13:30:00 GMT". It understands the continental US
time-zone abbreviations, but for general use, use a time-zone offset,
for example, "Mon, 25 Dec 1995 13:30:00 GMT+0430" (4 hours, 30 minutes
east of the Greenwich meridian). If you do not specify a time zone,
the local time zone is assumed. GMT and UTC are considered equivalent.
Alternatively, the date/time string may be in
ISO 8601 format. Starting with JavaScript 1.8.5 (Firefox 4), a subset
of ISO 8601 is supported. For example, "2011-10-10" (just date) or
"2011-10-10T14:48:00 (date and time) can be passed and parsed.
Clearly, these behave differently with respect to local timezones
Edit: Looks like this is implementation defined