40

I'm parsing a date from a JSON event feed - but the date shows "NaN" in IE7/8:

// Variable from JSON feed (using JQuery's $.getJSON)
var start_time = '2012-06-24T17:00:00-07:00';

// How I'm currently extracting the Month & Day
var d = new Date(start_time);
var month = d.getMonth();
var day = d.getDate();

document.write(month+'/'+day);// "6/24" in most browsers, "Nan/Nan" in IE7/8

What am I doing wrong? Thanks!

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Josiah
  • 1,117
  • 5
  • 22
  • 35

5 Answers5

69

In older browsers, you can write a function that will parse the string for you.

This one creates a Date.fromISO method- if the browser can natively get the correct date from an ISO string, the native method is used.

Some browsers got it partly right, but returned the wrong timezone, so just checking for NaN may not do.

Polyfill:

(function(){
    var D= new Date('2011-06-02T09:34:29+02:00');
    if(!D || +D!== 1307000069000){
        Date.fromISO= function(s){
            var day, tz,
            rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
            p= rx.exec(s) || [];
            if(p[1]){
                day= p[1].split(/\D/);
                for(var i= 0, L= day.length; i<L; i++){
                    day[i]= parseInt(day[i], 10) || 0;
                };
                day[1]-= 1;
                day= new Date(Date.UTC.apply(Date, day));
                if(!day.getDate()) return NaN;
                if(p[5]){
                    tz= (parseInt(p[5], 10)*60);
                    if(p[6]) tz+= parseInt(p[6], 10);
                    if(p[4]== '+') tz*= -1;
                    if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
                }
                return day;
            }
            return NaN;
        }
    }
    else{
        Date.fromISO= function(s){
            return new Date(s);
        }
    }
})()

Result:

var start_time = '2012-06-24T17:00:00-07:00';
var d =  Date.fromISO(start_time);
var month = d.getMonth();
var day = d.getDate();

alert(++month+' '+day); // returns months from 1-12
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • This is returning 5/24 in IE8 instead of 6/24 can you please update the function to work properly??? – segFault Mar 10 '13 at 06:57
  • Didn't change the function, just ++incremented the date.getMonth() in the alert to return a 1 based month. – kennebec Mar 10 '13 at 17:42
  • This works great, thanks you. Would really appreciate it if you could comment the code a bit to help us understand why you've done certain things e.g. +D!==1307000069000 – jackocnr Jun 04 '13 at 00:13
  • 2
    @jackocnr That took me a minute, too. The + casts D to a number. If it's a valid date, it's the same as D.getTime(), or 1307000069000. Otherwise, NaN. Not terribly readable, but clever. – visum Mar 06 '14 at 22:37
  • 1
    The regex should be updated to: rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):?(\d\d))?$/ Adding the question mark after the last colon, making it optional. The timezone offset often does not include the colon. (ex: "-400", "+0000") This is the format in PHP for the constant DateTime::ISO8601 yields no colon. – Nicholas E. Jul 06 '15 at 19:46
  • thaaaaaaanks :) – Szymon Nov 23 '16 at 11:30
25

For ie7/8 i just did:

var ds = yourdatestring;
ds = ds.replace(/-/g, '/');
ds = ds.replace('T', ' ');
ds = ds.replace(/(\+[0-9]{2})(\:)([0-9]{2}$)/, ' UTC\$1\$3');
date = new Date(ds);

This replaces all occurrences of "-" with "/", time marker "T" with a space and replaces timezone information with an IE-friendly string which enables IE7/8 to parse Dates from Strings correctly. Solved all issues for me.

Saul
  • 17,973
  • 8
  • 64
  • 88
Barbarossa
  • 808
  • 12
  • 24
5

See RobG's post at Result of toJSON() on a date is different between IE8 and IE9+.

Below function worked for me in IE 8 and below.

// parse ISO format date like 2013-05-06T22:00:00.000Z
function convertDateFromISO(s) {
  s = s.split(/\D/);
  return new Date(Date.UTC(s[0], --s[1]||'', s[2]||'', s[3]||'', s[4]||'', s[5]||'', s[6]||''))
}

You can test like below:

var currentTime = new Date(convertDateFromISO('2013-05-06T22:00:00.000Z')).getTime();
alert(currentTime);
Community
  • 1
  • 1
Estin Chin
  • 781
  • 7
  • 14
3

I suggest http://momentjs.com/ for cross browser date issues.

gib
  • 149
  • 1
  • 2
  • moment.js is a decent option. My issue is the size, so much of its girth is dedicated to handling things I dont care about. (eg. hebrew characters in date-time stamps) – The Dembinski Oct 24 '16 at 18:27
1

@gib Thanks for the suggestion on Moment.js. This small library really helps out with dealing with dates and JavaScript.

Moment.js solved the problem described in the original question that I was also having. IE8 was displaying JSON ISO dates as NaN when parsed into a new Date() object.

Quick solution (include moment.js in your page, or copy the code to your js functions include)

If you just need to display a date on your page, loaded from a JSON ISO date, do this:

order_date = moment(data.OrderDate); //create a "moment" variable, from the "data" object in your JSON function in Protoype or jQuery, etc.

$('#divOrderDate).html(order_date.calendar()); //use Moment's relative date function to display "today", "yesterday", etc.

or

order_date = moment(data.OrderDate); //create a "moment" variable, from the "data" object in your JSON function in Protoype or jQuery, etc.

$('#divOrderDate).html(order_date.format('m/d/YYYY')); //use Moment's format function to display "2/6/2015" or "10/19/2014", etc.  

If you must have a Date() object (say for use with jQuery Components), do the following so successfully populate your JSON provided ISO date. (This assumes you are already inside the function of handling your JSON data.)

var ship_date = new Date(moment(data.ShipDate).format('m/d/YYYY'));  //This will successfully parse the ISO date into JavaScript's Date() object working perfectly in FF, Chrome, and IE8.

//initialize your Calendar component with the "ship_date" variable, and you won't see NaN again.