Javascript date is invalid on iOS

Philipp Siegfried picture Philipp Siegfried · Nov 13, 2012 · Viewed 44.4k times · Source

I'm working on a Phonegap-based iOS app, which is already done for Android. The following lines are working fine for Android but not for iOS. Why?

var d = new Date("2015-12-31 00:00:00");
console.log(d.getDate() + '. ' + d.getMonth() + ' ' + d.getFullYear();

Result for Android:

31.11 2015

Result on iOS:

NaN. NaN NaN

Where is the difference coming from?

Answer

T.J. Crowder picture T.J. Crowder · Nov 13, 2012

Your date string is not in a format specified to work with new Date. The only format in the spec is a simplified version of ISO-8601, but that was only added in ES5 and so support may be touch and go. Your string isn't in that format, but it's really close.

If you change the space to a T, you'll be in spec:

var dateString = "2015-12-31 00:00:00";
var d = new Date(dateString.replace(' ', 'T'));

(I'm assuming you're not actually using a string literal, hence the replace call.)

Note that there was an error in the ES5 specification which was corrected in ES2015 (ES6): What happens when there's no timezone indicator on the string. In ISO-8601, no indicator means "local time," but the ES5 specification said that it defaults to Z (UTC —loosely, GMT). They fixed it in the ES2015 specification, but unfortunately some JavaScript engines followed the ES5 specification and others followed ISO-8601 (and now ES2015). But wait, it gets worse: Using local time for strings that just contained dates proved problematic for existing code (and TC39 really, really tries not to break existing code), so in ES2016 they had to change it again to say: If it's a date-only string, interpret it as UTC, but if it's a date/time string, interpret it as local time.

So with all of that fun and games, for solid cross-browser support, you need to include a timezone indicator, because otherwise you don't know whether it will be interpreted as UTC or local time. You're allowed to use Z for GMT or +/- followed by HH:MM to give an offset. (Abbreviations like CST are not allowed, as there's no standard for them.)

If they don't support that yet, there's near universal support for YYYY/MM/DD HH:MM:SS (interpreted as local time), even though it's not specified. So:

var dateString = "2015-12-31 00:00:00";
var d = new Date(dateString.replace(/-/g, '/'));