What is the input timezone for javascript `new Date` function? [duplicate] - javascript

In doing some testing I've found inconsistant behavior between browsers with the following javascript
new Date("2013-09-10T08:00:00").toString()
In IE and Firefox the result is
"Tue Sep 10 2013 08:00:00 GMT-0400 (Eastern Daylight Time)"
In Chrome the result is
"Tue Sep 10 2013 04:00:00 GMT-0400 (Eastern Daylight Time)"
So according to my reading of the ECMA script of the format for Date strings it says...
All numbers must be base 10. If the MM or DD fields are absent "01" is
used as the value. If the HH, mm, or ss fields are absent "00" is
used as the value and the value of an absent sss field is "000".
The value of an absent time zone offset is "Z"
However in the documentation for the "new Date()" constructor it says
15.9.3.2 new Date (value)
Let v be ToPrimitive(value).
If Type(v) is String, then
a. 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.
15.9.4.2 Date.parse (string)
The parse function applies the ToString operator to its argument and interprets the resulting String as a date
and time; it returns a Number, the UTC time value corresponding to the
date and time. 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.
Any ideas which implementation is correct?

Standards clash. ISO 8601 states that:
If no UTC relation information is given with a time representation, the time is assumed to be in local time.
ECMA says:
The value of an absent time zone offset is “Z”.
Mozilla devs think that ISO takes precedence, Chrome folks seem to disagree.
The current draft of ES6 says (under 20.3.1.15):
If the time zone offset is absent, the date-time is interpreted as a local time.
so Mozilla's implementation is (will be) correct.

There are several questions on stackoverflow.com that address this issue. I gave a rather thorough explanation here if anyone reading this is interested in the browser-to-browser details.
The bottom line though is, for now at least, you should either avoid the ISO 8601 format all together or ALWAYS include a timezone specifier when using it. And, never use the 'YYYY-MM-dd' format because it gets interpreted as a short version of ISO 8601 without a time zone specifier.

Related

What's the correct format of the default javascript Date returned object

When the new Date() is called, it returns something like this
Wed Jul 13 2022 16:15:35 GMT-0600 (Central Standard Time)
So I was curious what is the correct format used in that case? I tried building it with the following format: E MMM d yyyy H:mm:ss zzzz However the result was
Wed Jul 13 2022 16:15:00 GMT-06:00
This is the closest I can get. I've been searching the internet but can't find the correct format. By the way, the local used is en_US
Example:
let momentDate = moment(date, 'E MMM d yyyy H:mm:ss zzzz', true);
If I execute the momentDate.isValid() it returns false.
From MDN: Date.prototype.toString() returns a string representation of the Date in the format specified in ECMA-262.
That last part is described as:
Optionally, a timezone name consisting of:
space
Left bracket, i.e. "("
An implementation dependent string representation of the timezone, which might be an abbreviation or full name (there is no standard for names or abbreviations of timezones), e.g. "Line Islands Time" or "LINT"
Right bracket, i.e. ")"
Different date formatting libraries in different frameworks will have different ways to get a string representation of the time zone and, importantly, this is implementation-specific. This SO answer shows one way to get that value, basically by outputting it from a date and parsing the result. But you should not rely on it (or really any aspect of date outputs, apart from toISOString()) having any consistency between browsers or other execution environments.
Until ECMAScript 2018 (edition 9), the format of the string returned by Date.prototype.toString was implementation dependent. Therefore it should not be relied upon to be in the specified format.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toString#description
output variations are by design, and allowed by the specification... you cannot expect to be able to compare the results of toLocaleString() to a static value
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString#avoid_comparing_formatted_date_values_to_static_values

Difference between javascript string date formats [duplicate]

This question already has answers here:
Why does Date.parse give incorrect results?
(11 answers)
Closed 7 years ago.
I was executing below statement under nodejs repl and i was getting two different result for same date
var dateStr1 = "2015/03/31";
var dateStr2 = "2015-03-31";
var date1 = new Date(dateStr1);//gives Tue Mar 31 2015 00:00:00 GMT+0530 (IST)
var date2 = new Date(dateStr2);//gives Tue Mar 31 2015 05:30:00 GMT+0530 (IST)
In the 1st one hour,min,seconds are all zeros while in the 2nd one by default hour,min is getting set to as a timezone hour,min which is 5:30
It boils down to how Date.parse() handles the ISO-8601 date format.
The date time string may be in ISO 8601 format. For example, "2011-10-10" (just date) or "2011-10-10T14:48:00" (date and time) can be passed and parsed. The UTC time zone is used to interpret arguments in ISO 8601 format that do not contain time zone information (note that ECMAScript ed 6 draft specifies that date time strings without a time zone are to be treated as local, not UTC)
Your first date format 2015/03/31 is assumed to be March 31st, 2015 at 12am in your current time zone.
Your second date format 2015-03-31 is seen as ISO-8601 and is assumed to be March 31st, 2015 at 12am UTC time zone.
The "Differences in assumed time zone" heading from the linked documentation goes into a bit more detail:
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).
The first string, "2015/03/31", is an unsupported format according to the ECMAScript standard. Whenever an unsupported value is passed to the constructor its behaviour is implementation dependent, i.e. the standard doesn't say what the implementation must do. Some browsers, like Firefox, try to guess what the format is and apparently it creates a date object with that date at midnight local time. Other browsers may return NaN or interpret the parts differently.
The second string, "2015-03-31", is a properly formatted ISO 8601 date. For these strings there are well defined rules and all browsers will interpret it as that date, midnight, UTC.

Javascript converts date with timezone MESZ to NaN

I came across this date string:
2017-08-19T11:54:00MESZ
When I attempt to convert it as follows, it returns NaN:
let date = Date.parse("2017-08-19T11:54:00MESZ");
It appears that the ending on this string isn't recognized.
The format you're using is incorrect.
Take a look at this:
(new Date).toISOString()
"2017-08-19T10:05:18.700Z"
In contrast, the string you're trying to convert is:
"2017-08-19T11:54:00.MESZ"
Date.parse works with a variant of ISO8601 or RFC2822. Let's see how both options would work for you.
Working with ISO
It would accept either a UTC time zone descriptor ("Z") or a time zone offset (read on). Therefore the timezone instruction "MESZ" is invalid.
To reach a valid solution, you'd have to calculate the time zone offset from MESZ to Z, which is +2 hours, and append the the time expressed using wanted time zone:
Date.parse("2017-08-19T11:54:00+02:00")
1503136440000
Working with RFC2822
Example: "Mon, 25 Dec 1995 13:30:00 GMT"
Problem with RFC is that it does not accept any other time zone than GMT, UTC and Pacific, Central, Eastern, Mountain times which is not really useful for you right now. You're left off with the same problem: you'd have to express the date with a time zone offset instruction:
Date.parse("Sat, 19 Aug 2017 11:54:00 +0200")
1503136440000
You're basically stuck with UTC, but frankly it's probably a good thing in many ways.

What is the difference between new Date("2017-01-01") and new Date("2017-1-1")? [duplicate]

This question already has answers here:
Why isn't "2016-02-16" equal to "2016-02-16 00:00"?
(5 answers)
Closed 5 years ago.
I input new Date("2017-01-01") in chrome console, the output shows its hour is 8, but new Date("2017-01-1") and new Date("2017-1-01") shows their hour are both 0, so how does new Date(dateString) parse?
new Date("2017-01-01")
// Sun Jan 01 2017 08:00:00 GMT+0800 (中国标准时间)*
new Date("2017-01-1")
// Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)*
new Date("2017-1-1")
// Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)*
new Date("2017-1-01")
// Sun Jan 01 2017 00:00:00 GMT+0800 (中国标准时间)*
"2017-01-01" follows the ISO standard ES5 Date Time String format (simplification of ISO 8601 Extended Format), and therefore it is in UTC time, which is 8am in China. All other strings are parsed as local time in Chrome1.
1 Relevant source code in Chromium: https://cs.chromium.org/chromium/src/v8/src/dateparser-inl.h?type=cs&l=16
Date parsing in Chromium follows the standard ES5 rules as well as these extra rules:
Any unrecognized word before the first number is ignored.
Parenthesized text is ignored.
An unsigned number followed by : is a time value, and is added to the TimeComposer. A number followed by :: adds a second zero as well. A number followed by . is also a time and must be followed by milliseconds. Any other number is a date component and is added to DayComposer.
A month name (or really: any word having the same first three letters as a month name) is recorded as a named month in the Day composer.
A word recognizable as a time-zone is recorded as such, as is (+|-)(hhmm|hh:).
Legacy dates don't allow extra signs (+ or -) or unmatched ) after a number has been read (before the first number, any garbage is allowed).
Any strings that satisfy the ES5 rules and the rules above will be parsed using ES5 rules. This means "1970-01-01" will be in UTC time-zone not in local time-zone.
What does that mean?
First note that "2017-01-01" is parsed in UTC time because it is a "date" string instead of a "date-time" string, and it matches the ES5 definition of a "date" string. If time is attached, then it will follow the ISO standard and parse it in local time.
Examples:
2017-01-01 - Jan 1, 2017 in UTC time
2017-01-01T00:00 - Jan 1, 2017 in local time
2017-1-1 - Jan 1, 2017 in local time
2017-(hello)01-01 - Jan 1, 2017 in local time
may 2017-01-01 - May 1, 2017 in local time
mayoooo 2017-01-01 - May 1, 2017 in local time
"jan2017feb-mar01apr-may01jun" - Jun 1, 2017 in local time
difference between new Date("2017-01-01") and new Date("2017-1-1")
new Date("2017-01-01") is in-spec (more below). new Date("2017-1-1") is not, and so falls back on any "...implementation-specific heuristics or implementation-specific date formats" the JavaScript engine wants to apply. E.g., you have no guarantee how (or whether) it will successfully parse and if so, whether it will be parsed as UTC or local time.
Although new Date("2017-01-01") is in-spec, sadly what browsers are supposed to do with it has been a moving target, because it doesn't have a timezone indicator on it:
In ES5 (December 2009), strings without a timezone indicator were supposed to be parsed as UTC. But that's at variance with the ISO-8601 standard the date/time format is based on, which says strings without a timezone indicator are meant to be local time, not UTC. So in ES5, new Date("2017-01-01") is parsed in UTC.
In ES2015 (aka ES6, June 2015), strings without a timezone indicator were supposed to be local time, not UTC, like ISO-8601. So in ES2015, new Date("2017-01-01") is parsed as local time.
But, that was changed again in ES2016 (June 2016) because browsers had been parsing date-only forms with - in them as UTC for years. So as of ES2016, date-only forms (like "2017-01-01") are parsed in UTC, but date/time forms (like "2017-01-01T00:00:00") are parsed in local time.
Sadly, not all JavaScript engines currently implement the spec. Chrome (as of this writing, v56) parses date/time forms in UTC even though they should be local time (so does IE9). But Chrome, Firefox, and IE11 (I don't have IE10 or Edge handy) all handle date-only forms correctly (as UTC). IE8 doesn't implement the ISO-8601 form at all (having been released before the ES5 spec was released).
When parsing dates, JavaScript interprets ISO dates as UTC time and other formats as local time.
As MDN article suggests,
Where the string is ISO 8601 date only, the UTC time zone is used to interpret arguments.
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 (ES5 and ECMAScript 2015). 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.
// 2017-03-28 is interpreted as UTC time,
// shown as 2017-03-28 00:00:00 in UTC timezone,
// shown as 2017-03-28 06:00:00 in my timezone:
console.log("ISO dates:");
var isoDates = [new Date("2017-03-28")];
for (var dt of isoDates)
{
console.log(dt.toUTCString() + " / " + dt.toLocaleString());
}
// Other formats are interpreted as local time,
// shown as 2017-03-27 18:00:00 in my timezone,
// shown 2017-03-28 00:00:00 in my timezone:
console.log("Other formats:");
var otherDates = [new Date("2017-3-28"), new Date("March 28, 2017"), new Date("2017/03/28")];
for (var dt of otherDates)
{
console.log(dt.toUTCString() + " / " + dt.toLocaleString());
}
This format is International Standard (ISO format)
new Date("2017-01-01")
This guarantees same output across all browsers.
However, the other formats may change according to browser as they are not so well defined.
As you can see that this format
new Date("2017-1-1")
is parsed successfully in chrome, but gives error in IE 11

Why isn't "2016-02-16" equal to "2016-02-16 00:00"?

I'm trying to pass both date strings to new Date(t).
I expect both strings represent the same time, after all, if I omit the time, shouldn't it be midnight of that day?
But while,
new Date("2016-02-16 00:00")
returns 2016-02-16, midnight, local time as expected,
new Date("2016-02-16")
returns 2016-02-16, midnight UTC, which is wrong, or at least not what I expected given what the other string parses as.
I would understand it if they would both have the same behavior, whether it is to return the time as local time, or as UTC, but it seems very inconsistent why they return different things like this.
As a workaround, whenever I encounter a date that has no corresponding timestamp I can append " 00:00" to get consistent behavior, but it seems like this is rather fragile.
I am getting this value from an INPUT element, of type 'datetime-local' so it seems especially inconsistent that I have to work around a value returned by a page element.
Am I doing something wrong, or should I be doing something differently?
It's what the ES5.1 specification says to do:
The value of an absent time zone offset is “Z”.
It also says:
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.
Since the format requires a T separator between date and time, the valid times go to UTC:
> new Date("2016-02-16T00:00:00")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
> new Date("2016-02-16")
Tue Feb 16 2016 01:00:00 GMT+0100 (CET)
...while in node.js, an invalid time (without the T separator) seems to go to the implementation specific localtime:
> new Date("2016-02-16 00:00:00")
Tue Feb 16 2016 00:00:00 GMT+0100 (CET)
Note that ES6 changed this, in the same part of the documentation it changes to:
If the time zone offset is absent, the date-time is interpreted as a local time.
The joy of breaking changes.
Edit
According to TC39, the specification is meant to be interpreted as date and time strings without a time zone (e.g. "2016-02-16T00:00:00") are treated as local (per ISO 8601), but date only strings (e.g. "2016-02-16") as UTC (which is inconsistent with ISO 8601).
According to the specifications:
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 Date Time String Formats accept 2016-02-16 as a valid date
This format includes date-only forms:
YYYY
YYYY-MM
YYYY-MM-DD
[...] If the HH, mm, or ss fields are absent “00” is used as the value
and the value of an absent sss field is “000”. The value of an absent
time zone offset is “Z”.
Thus 2016-02-16 translates to 2016-02-16T00:00:00.000Z.
The other date 2016-02-16 00:00 does not conform to the format and therefore its parsing is implementation specific. Apparently, such dates are treated as having local time zone and your example date will return different values depending on time zone:
/* tz = +05:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-15T19:00:00.000Z
/* tz = -08:00 */ new Date("2016-02-16 00:00").toISOString() // 2016-02-16T08:00:00.000Z
Summary:
For conforming date time formats the behavior is well defined — in the absence of time zone offset the date string is treated as UTC (ES5) or local (ES6).
For non-conforming date time formats the behavior is implementation specific — in the absence of time zone offset the usual behavior is to treat the date as local.
As a matter of fact, the implementation could choose to return NaN instead of trying to parse non-conforming dates. Just test your code in Internet Explorer 11 ;)
You are perhaps running into a differences between ES5, ES6 implementations and your expected result. Per Date.parse at MDN, "especially across different ECMAScript implementations where strings like "2015-10-12 12:00:00" may be parsed to as NaN, UTC or local timezone" is significant.
Additional testing in Firefox 44 and IE 11 revealed they both return a date object for new Date("2016-02-16 00:00"), which object returns NaN when atttempting to get a date component value, and whose toString value is
"Invalid Date" (not "NaN"). Hence appending " 00:00 to get consistent behavior" can easily break in different browsers.
As noted in other answers new Date("2016-02-16") uses a timezone offset of zero by default, producing midnight UTC instead of local.
Per DateParser::Parse() of V8 source codes for Chrome.
ES5 ISO 8601 dates:
[('-'|'+')yy]yyyy[-MM[-DD]][THH:mm[:ss[.sss]][Z|(+|-)hh:mm]]
An unsigned number followed by ':' is a time value, and is added to the TimeComposer.
timezone defaults to Z if missing
> new Date("2016-02-16 00:00")
Tue Feb 16 2016 00:00:00 GMT+0800 (China Standard Time)
A string that matches both formats (e.g. 1970-01-01) will be parsed as an ES5 date-time string - which means it will default to UTC time-zone. That's unavoidable if following the ES5 specification.
> new Date("2016-02-16")
Tue Feb 16 2016 08:00:00 GMT+0800 (China Standard Time)
returns 2016-02-16, midnight UTC, which is wrong, or at least not what I expected given what the other string parses as.
It adds the timezone offset to the 00:00
new Date("2016-02-16") outputs Tue Feb 16 2016 05:30:00 GMT+0530 (India Standard Time)
My timezone being IST with an offset value (in minutes) +330, so it added 330 minutes to 00:00.
As per ecma-262, section 20.3.3.2 Date.parse ( string )
If ToString results in an abrupt completion the Completion Record is
immediately returned. Otherwise, parse interprets the resulting String
as a date and time; it returns a Number, the UTC time value
corresponding to the date and time. 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.
When you explicitly set the time-units new Date("2016-02-16 00:00") it wll use set that as hours and minutes,
Otherwise as stated here in 20.3.1.16
If the time zone offset is absent, the date-time is interpreted as a
local time.

Categories