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?
Tue Jun 21 2011 10:27:28 GMT-0400 (Eastern Daylight Time)
new Date(Date.parse(string))
is redundant since if the Date constructor is called with a string, it's passed to Date.parse anyway. Also, Safari has a few bugs with creating dates that are difficult (if not impossible) to work around.
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);
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);
The UTC offset is appended to the time in the same way that 'Z' was above, in the form ±[hh]:[mm], ±[hh][mm], or ±[hh].
And indeed, Chrome & Firefox are able to parse the offsets without colons
new Date("2020-04-16T20:00+04:00"))
works as well across browsers (Chrome, Firefox, Safari, Edge).
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);
}
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(/(\..*|\+.*/,""))
new Date("2016-02-17T00:05:01+0000".replace(/-/g,'/').replace('T',' ').replace(/\..*|\+.*/,""))
.replace(/-/g,'/')
works. my datestring is like this "2019-06-26 23:59:59"
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
/[a-z]+/gi
, to match a wider audience, like dates with UTC instead of only T.
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.
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());
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'));
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);
Use this to both (Safari / Chrome):
Date.parse("2018-02-06T20:00:00.000-03:00")
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'));
Success story sharing