Date parsing in javascript is different between safari and chrome

JavascriptParsingDateGoogle ChromeSafari

Javascript 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'));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbradgonesurfingView Question on Stackoverflow
Solution 1 - JavascriptErikView Answer on Stackoverflow
Solution 2 - JavascriptOlmstovView Answer on Stackoverflow
Solution 3 - JavascriptjableyView Answer on Stackoverflow
Solution 4 - JavascriptKooiIncView Answer on Stackoverflow
Solution 5 - JavascriptLonderenView Answer on Stackoverflow
Solution 6 - JavascriptAaronSiebView Answer on Stackoverflow
Solution 7 - JavascriptadjwilliView Answer on Stackoverflow
Solution 8 - JavascriptAdam LeggettView Answer on Stackoverflow
Solution 9 - JavascriptAnkyView Answer on Stackoverflow
Solution 10 - JavascriptIvan FerrerView Answer on Stackoverflow
Solution 11 - JavascriptschnereView Answer on Stackoverflow