I want to convert date string to Date by javascript, use this code:
var date = new Date('2013-02-27T17:00:00');
alert(date);
'2013-02-27T17:00:00' is UTC time in JSON object from server.
But the result of above code is different between Firefox and Chrome:
Firefox returns:
Wed Feb 27 2013 17:00:00 GMT+0700 (SE Asia Standard Time)
Chrome returns:
Thu Feb 28 2013 00:00:00 GMT+0700 (SE Asia Standard Time)
It's different 1 day, the correct result I would expect is the result from Chrome.
Demo code: http://jsfiddle.net/xHtqa/2/
How can I fix this problem to get the same result from both?
The correct format for UTC would be 2013-02-27T17:00:00Z (Z is for Zulu Time). Append Z if not present to get correct UTC datetime string.
Yeah, unfortunately the date-parsing algorithms are implementation-dependent. From the specification of Date.parse (which is used by new Date):
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.
To make the Date constructor not (maybe) use the local timezone, use a datetime string with timezone information, e.g. "2013-02-27T17:00:00Z". However, it is hard to find a format that is reliable parsed by every browser - the ISO format is not recognised by IE<8 (see JavaScript: Which browsers support parsing of ISO-8601 Date String with Date.parse). Better, use a unix timestamp, i.e. milliseconds since unix epoch, or use a regular expression to break the string down in its parts and then feed those into Date.UTC.
I found one thing here. It seems the native Firefox Inspector Console might have a bug:
If I run "new Date()" in the native Inspector, it shows a date with wrong timezone, GMT locale, but running the same command in the Firebug Extension Console, the date shown uses my correct timezone (GMT-3:00).
Noticed that FireFox wasn't returning the same result as Chrome. Looks like the format you use in kendo.toString for date makes a difference.
The last console result is what I needed:
Try using moment.js. It goes very well and in similar fashion with all the browsers. comes with many formatting options. use moment('date').format("") instead of New Date('date')
Related
Strange thing, different results in differente browser for a new Date().
In Chrome 45.0.2454.101 m:
new Date(2015,9,1)
Thu Oct 01 2015 00:00:00 GMT+0200 (W. Europe Daylight Time)
In Firefox 40.0.3 (default inspector/console)
new Date(2015,9,1)
Date 2015-09-30T22:00:00.000Z
Additional info
If I try in Firefox with the console of FIREBUG extension, works well like Chrome.
What's happening? Seems that Firefox doen'st count the offset, in fact it's 2 hour behind the correct date.
I did the test on other workstation and all seems to have this "bug".
IF you don't want the timezone offset to be included you can use Date.UTC
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.
~MDN
Output from Firefox dev console:
> new Date(2015,9,1)
Date 2015-09-30T22:00:00.000Z // reproduces your problem, my local time is GMT+0200
> new Date(Date.UTC(2015,9,1))
Date 2015-10-01T00:00:00.000Z // UTC time
However 00:00:00 GMT+0200 and 22:00:00.000Z are just different ways to represent the timezone offset in Date's string representation. The difference is the method used when printing to console: most browsers use .toString() while Firefox uses .toISOString(). (Edited; previously stated that the toString method implementations are different which isn't true).
In both Chrome (Thu Oct 01 2015 00:00:00 GMT+0200) and Firefox (Date 2015-09-30T22:00:00.000Z) methods like .getDate() and .getMonth() return the same values (1 and 9 respectively). The Date objects are the same.
This is just the behavior of the debug console. The two date values you showed are both the same, and are the correct value. You're just seeing the local time in Chrome, while Firefox chooses to show the UTC time in the debug console.
More accurately, Chrome, IE, and most other browsers simply call .toString() on the object, while Firefox is calling .toISOString().
Note that Firefox has a bug that us showing the wrong name of the time zone (Standard instead of Daylight), but you can see the debugger value matches the ISO8601 UTC value.
Chrome not giving a correct result on date conversion:
Date : "2017-05-22T14:00:00"
On doing this in chrome console:
new Date("2017-05-22T14:00:00");
Output is:
Mon May 22 2017 14:00:00 GMT+0530 (IST)
This is wrong because I am in IST. It should have rather given output as
Mon May 22 2017 19:30:00 GMT+0530 (IST)
Safari is giving correct results. Chrome was right before but I think latest update is having an issue.
Found that appending Z in date string results correct date value.
new Date("2017-05-22T14:00:00Z");
The input value is being interpreted correctly. ECMAScript 2015 (ES6) section 20.3.1.16 states:
If the time zone offset is absent, the date-time is interpreted as a local time.
This aligns with the ISO-8601 standard as well.
In previous versions of ECMAScript, UTC was assumed when no offset was provided. That goes against ISO-8601, and was implemented inconsistently across various environments.
If you want the input to be interpreted as UTC, then you should provide an offset, either +00:00, or Z as part of the input string.
However, if you are talking about how a Date object should be displayed when logged to the debug console, that is not defined in the spec. In some environments, you will see the output of date.toString(), which shows the local date and time in a non-standard format, and in other environments (such as FireFox) you will see the output of date.toISOString(), which shows the UTC date and time in ISO-8601 format.
There's no spec about which to show, so either would be valid. If you want to see specific output, don't just log a Date object, call a function on the object that returns a string and log that instead.
I am formatting a given date using momentjs. The following behaves differently in different timezones:
moment(new Date("2016" + "-" + "06" + "-01").toISOString()).format('MMMM YYYY')
It gives me May 2016 in timezone of America/Denver and June 2016 in Asia/Karachi. I tested by changing the browser timezone to different timezones. It should be June 2016 in both.
When i change the format in new Date() to use slashes instead of hyphens like below, it gives me correct result in both timezones i.e. May 2016.
moment(new Date("2016" + "/" + "06" + "/01").toISOString()).format('MMMM YYYY')
Both seem to be valid ISO strings, what would cause this inconsistency?
The short answer to your question is that parser for javascript date doesn't work in a way that makes sense to anybody. Instead, you should just use Moment's parser to get the result you want. Parsing dates in a way that makes sense is about 50% of the reason that moment exists.
If you eliminate the date call and use Moment to parse your date, you will observe that the following code will result in June 2016 in any browser, because your string will be interpreted as local time if you are using Moment's default constructor:
moment('2016-06-01').format()
If you wanted to use slashes instead, it would be:
moment('2016/06/01', 'YYYY/MM/DD').format()
See moment's parsing guide for more information about how moment interprets times with it's different constructor methods.
The long answer is that when you pass a string in ISO8601 format that is date only to the JavaScript date constructor, it will interpret that string as UTC. Because Denver is UTC -6 on daylight time, and Karachi is UTC +5 all the time, when moment then displays that timestamp as local time you see the result that you do. You can observe the following:
var a = new Date('2016-06-01');
a.toISOString();
"2016-06-01T00:00:00.000Z"
Note that the 'Z' in the above timestamp indicates that it is UTC, as toISOString always returns a UTC timestamp. That timestamp is June in Karachi because Karachi is ahead of UTC, while May in Denver because Denver is behind UTC.
Observe this as well:
var a = new Date('2016-06-01T00:00');
a.toISOString();
"2016-06-01T05:00:00.000Z"
If I put a time on my string, it is interpreted as local time. Because my timezone was UTC-5 on January 1, the point on the global timeline is appropriately five hours ahead of the string I passed.
The behavior you are seeing - interpreting 2016-06-01 as UTC, but 2016-06-01T00:00 as local, is actually an effort to accommodate technical debt across browsers. It has been made the standard behavior in the 7th edition of the ECMA 262 specification, so expect for that not to change. See this link as well.
Alternately, when you use the slashes (2016/06/01) the JS implementation that you are using is choosing to interpret that format as local time, as it does not conform to any of the formats in the ECMA standard. This is NOT a valid ISO8601 format. It is very important to note that this behavior is implementation specific, and will vary across browsers/environments. The ECMA standard does not define a behavior for parsing that date format. Other browsers may parse this string in other ways.
As general advice, don't use the JavaScript date parser. It doesn't work right. You can use Moment.js, one of moment's several competitors, or manually parse strings yourself. All of these are better options.
I am looking for a date format (only year, month and day, no time component), that will be guaranteed to be interpreted as local time, in all reasonably modern browsers, when passed to the Date() constructor in JavaScript.
The (3-letter English month abbreviation) (2-digit date) (4-digit year) format seems to work. When I do new Date('Apr 01 2015') on my English system, in Chrome, with my machine being in the Eastern timezone, I get back Wed Apr 01 2015 00:00:00 GMT-0400 (Eastern Daylight Time) which is exactly what I want.
However, I am not sure if this (3-letter English month abbreviation) (2-digit date) (4-digit year) format is guaranteed to be interpreted in the same way regardless of browser and browser/OS locale/language.
Will this format work the same way across different (reasonably modern) browsers and locales? If not, then is there some other format that will work?
Please note that ISO-8601 doesn't answer this question. ISO-8601 date-only strings are interpreted as being in UTC, and not in local time, so new Date('2015-04-01') is interpreted as Tue Mar 31 2015 20:00:00 GMT-0400 (Eastern Daylight Time), i.e. April 1 turns into March 31, which is not what I'm looking for.
I am looking for a date format (only year, month and day, no time component), that will be guaranteed to be interpreted as local time, in all reasonably modern browsers, when passed to the Date() constructor in JavaScript.
There isn't one. There are a number of formats that, in practice, are reliably parsed by all browsers in use however none of them are required by ECMA-262 to be supported by ECMAScript implementations.
There is one format, a version of ISO 8601, that is specified in ES5 and ECMAScript 2015 however dates without a time zone are to be treated as UTC in ES5 and "local" in ECMAScript 2015.
But that was seen by implementers as "breaking the web", so while some browsers implemented that for a while, they have now reverted to ES5 behaviour and treat a missing timezone as UTC.
A small change in format such as changing the separator from "-" to "/" causes a reversion to implementation dependent behaviour and may cause the date to be treated as UTC or local (though most seem to treat 2015/12/17 as local).
So if you want a guarantee, there isn't one. However, if you are prepared to write a 2 line function, you can parse an ISO 8601 like string reliably based on whatever time zone you like. If you want it to be treated as local (i.e. set to 00:00:00 and offset based on system settings), then:
function parseISOLike(s) {
var b = s.split(/\D/);
return new Date(b[0], b[1]-1, b[2])
}
document.write(parseISOLike('2015-12-17'));
will do the job (without checking for valid values) and allow the separator to be any non–digit, so 2015/12/17, 2015-12-17 and 2015.12.17 will all be correctly parsed.
Edit
Parts of the above have been edited thanks to input from Matt Johnson.
The implementation of Date.parse in Chrome has very unexpected behavior.
For example, Date.parse('foo 2014') should ideally return NaN as it is not a proper date format. But in Chrome this returns the value 1388514600000, which is equivalent to the date "Wed Jan 01 2014 00:00:00 GMT+0530 (India Standard Time)".
As long as the string ends with some sort of year, a proper date value is returned. This will not let us to properly validate dates.
According to ECMAScript this behavior is implementation dependent and chrome does a very loose validation and some how converts to a date.
Is there anyway in chrome to properly validate date without using any library or using heavy logic and matching patterns?
You can test date string with regular expression before parse.