Date parsing in javascript is different between safari and chrome
JavascriptParsingDateGoogle ChromeSafariJavascript Problem Overview
I have the following code
var c = new Date(Date.parse("2011-06-21T14:27:28.593Z"));
console.log(c);
On Chrome it correctly prints out the date on the console. In Safari it fails. Who is correct and more importantly what is the best way to handle this?
Javascript Solutions
Solution 1 - Javascript
You can't really use Date.parse. I suggest you use: new Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )
To split the string you could try
var s = '2011-06-21T14:27:28.593Z';
var a = s.split(/[^0-9]/);
//for (i=0;i<a.length;i++) { alert(a[i]); }
var d=new Date (a[0],a[1]-1,a[2],a[3],a[4],a[5] );
alert(s+ " "+d);
Solution 2 - Javascript
My similar issue was caused by Safari not knowing how to read the timezone in a RFC 822 time zone format. I was able to fix this by using the ISO 8601 format. If you have control of the date format I got this working with java's SimpleDateFormat "yyyy-MM-dd'T'HH:mm:ss.sssXXX" which produces for me ie. "2018-02-06T20:00:00.000+04:00". For whatever reason Safari can't read "2018-02-06T20:00:00.000+0400", notice the lack of colon in the timezone format.
// Works
var c = new Date("2018-02-06T20:00:00.000+04:00"));
console.log(c);
// Doesn't work
var c = new Date("2018-02-06T20:00:00.000+0400"));
console.log(c);
Solution 3 - Javascript
I tend to avoid Date.parse
, as per the other answers for this question. It doesn't seem to be a portable way to reliably deal with dates.
Instead, I have used something like the function below. This uses jQuery to map the string array into a number array, but that's a pretty easy dependency to remove / change. I also include what I consider sensible defaults, to allow you to parse 2007-01-09
and 2007-01-09T09:42:00
using the same function.
function dateFromString(str) {
var a = $.map(str.split(/[^0-9]/), function(s) { return parseInt(s, 10) });
return new Date(a[0], a[1]-1 || 0, a[2] || 1, a[3] || 0, a[4] || 0, a[5] || 0, a[6] || 0);
}
Solution 4 - Javascript
I've checked it in several browsers, and yes, safari returns invalid date
. By the way, you don't have to use Date.parse
here, just new Date([datestring])
will work too. Safari evidently requires more formatting of the datestring you supply. If you replace '-' with '/', remove the T and everything after the dot (.593Z), it will give you a valid date. This code is tested and works in Safari
var datestr = '2011-06-21T14:27:28.593Z'.split(/[-T.]/);
var safdat = new Date( datestr.slice(0,3).join('/')+' '+datestr[3] );
Or using String.replace(...)
:
new Date("2016-02-17T00:05:01+0000".replace(/-/g,'/').replace('T',' ').replace(/(\..*|\+.*/,""))
Solution 5 - Javascript
I use the following function for parsing dates with timezone. Works fine both Chrome and Safari:
function parseDate(date) {
const parsed = Date.parse(date);
if (!isNaN(parsed)) {
return parsed;
}
return Date.parse(date.replace(/-/g, '/').replace(/[a-z]+/gi, ' '));
}
console.log(parseDate('2017-02-09T13:22:18+0300')); // 1486635738000 time in ms
Solution 6 - Javascript
I ended up using a library to offset this:
http://zetafleet.com/blog/javascript-dateparse-for-iso-8601
Once that library was included, you use this code to create the new date:
var date = new Date(Date.parse(datestring));
Our project wasn't using millisecond specifiers, but I don't believe that will cause an issue for you.
Solution 7 - Javascript
Instead of using 'Z' at the end of the date string, you can add the local client timezone offset. You'll probably want a method to generate that for you:
let timezoneOffset = () => {
let date = new Date(),
timezoneOffset = date.getTimezoneOffset(),
hours = ('00' + Math.floor(Math.abs(timezoneOffset/60))).slice(-2),
minutes = ('00' + Math.abs(timezoneOffset%60)).slice(-2),
string = (timezoneOffset >= 0 ? '-' : '+') + hours + ':' + minutes;
return string;
}
So the end result would be:
var c = new Date("2011-06-21T14:27:28.593" + timezoneOffset());
Solution 8 - Javascript
Here is a more robust ISO 8601 parser than what others have posted. It does not handle week format, but it should handle all other valid ISO 8601 dates consistently across all browsers.
function newDate(value) {
var field = value.match(/^([+-]?\d{4}(?!\d\d\b))(?:-?(?:(0[1-9]|1[0-2])(?:-?([12]\d|0[1-9]|3[01]))?)(?:[T\s](?:(?:([01]\d|2[0-3])(?::?([0-5]\d))?|24\:?00)([.,]\d+(?!:))?)?(?::?([0-5]\d)(?:[.,](\d+))?)?([zZ]|([+-](?:[01]\d|2[0-3])):?([0-5]\d)?)?)?)?$/) || [];
var result = new Date(field[1], field[2] - 1 | 0, field[3] || 1, field[4] | 0, field[5] | 0, field[7] | 0, field[8] | 0)
if (field[9]) {
result.setUTCMinutes(result.getUTCMinutes() - result.getTimezoneOffset() - ((field[10] * 60 + +field[11]) || 0));
}
return result;
}
console.log(newDate('2011-06-21T14:27:28.593Z'));
console.log(newDate('1970-12-31T06:00Z'));
console.log(newDate('1970-12-31T06:00-1200'));
Solution 9 - Javascript
i tried converted date by truncating it and parsing it like that , its working fine with safari and ios .
var dateString = "2016-01-22T08:18:10.000+0000";
var hours = parseInt(dateString.split("+")[1].substr("0","2"));
var mins = parseInt(dateString.split("+")[1].substr("2"));
var date = new Date(dateString.split("+")[0]);
date.setHours(date.getHours()-hours);
date.setMinutes(date.getMinutes()-mins);
Solution 10 - Javascript
Use this to both (Safari / Chrome):
Date.parse("2018-02-06T20:00:00.000-03:00")
Solution 11 - Javascript
Instead of using a 3rd party library, this is my - relatively simple - solution for this:
function parseDateTime(datetime, timezone) {
base = new Date(datetime.replace(/\s+/g, 'T') + 'Z');
hoursUTC = base.toLocaleTimeString('de-AT',{ timeZone: 'UTC' }).split(':')[0];
hoursLocal = base.toLocaleTimeString('de-AT',{ timeZone: 'Europe/Vienna' }).split(':')[0];
timeZoneOffsetSign = (hoursLocal-hoursUTC) < 0 ? '-':'+';
timeZoneOffset = Math.abs(hoursLocal-hoursUTC);
timeZoneOffset = timeZoneOffsetSign + timeZoneOffset.toString().padStart(2, '0') + ':00';
return new Date(datetime.replace(/\s+/g, 'T') + timeZoneOffset);
}
localDate = parseDateTime('2020-02-25 16:00:00','Europe/Vienna');
console.log(localDate);
console.log(localDate.toLocaleString('de-AT','Europe/Vienna'));