94

I need help/tips on converting an ISO 8601 date with the following structure into JavaScript:

CCYY-MM-DDThh:mm:ssTZD

I'd like to format the date like so:

January 28, 2011 - 7:30PM EST

I'd like to keep this solution as clean and minimal as possible.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Slythic
  • 1,853
  • 2
  • 15
  • 14
  • 1
    I know this is an old post, but this library does what you want: https://github.com/csnover/js-iso8601 – Steve Nov 16 '12 at 22:56

5 Answers5

126

The Date object handles 8601 as its first parameter:

var d = new Date("2014-04-07T13:58:10.104Z");
console.log(d.toString());
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Rob Evans
  • 6,750
  • 4
  • 39
  • 56
  • 10
    Not in all browsers. Keep in mind, ECMA specification was or still is vague about the parameter format of Date(). That's why even IE11 can't handle what you are suggesting. – René Stalder May 27 '14 at 08:51
  • 1
    @RenéStalder I actually just tested this in IE11 and it works. Did you test in other IE versions? – Rob Evans Jul 01 '14 at 10:51
  • 14
    @RenéStalder Just tested in IE9 on Win7 too and it works there as well. In fact so far I haven't found a single browser that doesn't support it. – Rob Evans Jul 01 '14 at 10:54
  • Well, as said, it differs, depending on the string format you are using. It might be possible that some work in some browsers, some others work in some other browsers. Because the specification isn't clear enough. See http://stackoverflow.com/a/20803976/317428 for another example. – René Stalder Jul 02 '14 at 13:45
  • This answer is beautiful, simple, and correct. This even prints the time adjusted to the local time of the user. Doing anything else is silly! (**edit:** I am using jQuery if that changes anything for those who come after.) – e.thompsy Mar 11 '15 at 15:22
  • 2
    Doesn't work in IE 9: Quirks mode for sure. Some of us need browser compatability. – SR Bhaskar Jul 06 '15 at 15:14
  • It has strange behavior in the latest Chome: the timezone of the resulting Date object is converted to local time zone. I.e. in my current timezine new Date("2015-10-24T08:00:00") = Sat Oct 24 2015 16:00:00 GMT+0800 – Sergey Kandaurov Oct 27 '15 at 15:25
  • 4
    Date parsing is implementation dependent until ES5. Old browsers will display inconsistent results. – Mrchief Apr 01 '16 at 16:10
  • Thanks, this is the solution that allowed me tu use getHours, e.g var h = new Date("2014-04-07T13:58:10.104Z").getHours(); – moodymudskipper May 03 '16 at 08:49
  • Best answer. For those who need browser compatibility before IE9, https://github.com/csnover/js-iso8601 – j4k3 Oct 13 '16 at 07:46
  • 1
    [quote from Mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date): "Parsing of date strings with the Date constructor (and Date.parse(), which works the same way) is strongly discouraged due to browser differences and inconsistencies." – JHBonarius Jul 13 '20 at 09:01
  • 1
    @JHBonarius its true that is written. The testable objective reality is that if you pass the format I quoted above, the output is consistent in all the browsers people use today. – Rob Evans Jan 22 '21 at 13:56
  • ES6 explicitly supports ISO 8601 dates, so this is the right approach unless you need to support legacy browsers. – Nick McCurdy Sep 26 '22 at 09:59
35

datejs could parse following, you might want to try out.

Date.parse('1997-07-16T19:20:15')           // ISO 8601 Formats
Date.parse('1997-07-16T19:20:30+01:00')     // ISO 8601 with Timezone offset

Edit: Regex version

x = "2011-01-28T19:30:00EST"

MM = ["January", "February","March","April","May","June","July","August","September","October","November", "December"]

xx = x.replace(
    /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):\d{2}(\w{3})/,
    function($0,$1,$2,$3,$4,$5,$6){
        return MM[$2-1]+" "+$3+", "+$1+" - "+$4%12+":"+$5+(+$4>12?"PM":"AM")+" "+$6
    }
)

Result

January 28, 2011 - 7:30PM EST

Edit2: I changed my timezone to EST and now I got following

x = "2011-01-28T19:30:00-05:00"

MM = {Jan:"January", Feb:"February", Mar:"March", Apr:"April", May:"May", Jun:"June", Jul:"July", Aug:"August", Sep:"September", Oct:"October", Nov:"November", Dec:"December"}

xx = String(new Date(x)).replace(
    /\w{3} (\w{3}) (\d{2}) (\d{4}) (\d{2}):(\d{2}):[^(]+\(([A-Z]{3})\)/,
    function($0,$1,$2,$3,$4,$5,$6){
        return MM[$1]+" "+$2+", "+$3+" - "+$4%12+":"+$5+(+$4>12?"PM":"AM")+" "+$6 
    }
)

return

January 28, 2011 - 7:30PM EST

Basically

String(new Date(x))

return

Fri Jan 28 2011 19:30:00 GMT-0500 (EST)

regex parts just converting above string to your required format.

January 28, 2011 - 7:30PM EST
julen
  • 4,959
  • 1
  • 23
  • 31
YOU
  • 120,166
  • 34
  • 186
  • 219
  • I'm making a widget and would prefer if I could just have a simple function which I could throw in my JS file. I think datajs might be overkill for this? Thanks for the suggestion and quick reply!! – Slythic Jan 28 '11 at 15:07
  • @Slythic, I will write regex then, pls hold on. – YOU Jan 28 '11 at 15:13
  • @Slythic, Updated, let me know if there is any bug. – YOU Jan 28 '11 at 15:28
  • Hmm... not working as expected. I should have added this before! Here is an example of a returned date: "2011-01-28T19:30:00-05:00" – Slythic Jan 28 '11 at 15:46
  • ah, ok, timezone is not a string, let me figure out, how to parse that. – YOU Jan 28 '11 at 15:51
  • @Slythic, looks like converting -05:00 to EST hard to be done, because javascript run on local, built-in Date() function returns my time zone JST instead of EST, so probably might need to embed timezone info in the codes. and looks like datejs library also hard coding partial timezone data [here](http://code.google.com/p/datejs/source/browse/trunk/src/globalization/en-US.js) (Look for timezone) – YOU Jan 28 '11 at 16:20
  • S.Mark - Thanks so much for giving it a try! I know this script DOES format the EST. Any clues in it that can help you figure it out? http://n8v.enteuxis.org/2010/12/parsing-iso-8601-dates-in-javascript/ – Slythic Jan 28 '11 at 16:24
  • @Slythic, It gave me `parseISO8601Date("2011-01-28T19:30:00-05:00" ) Fri Jan 28 2011 23:30:00 GMT+0900 (JST)` I think you're in EST timezone, so thats why probably giving you EST. But, If you are ok with local timezone setting I could change my regex to make that work (it will give you EST, but for me it will return JST). – YOU Jan 28 '11 at 16:29
  • Getting an 'Invalid Date'. I pretty much copied and pasted your second edit like I did your first edit. Able to make your first edit work but not the second edit. Trying to figure out what I'm missing... – Slythic Jan 28 '11 at 17:11
  • This is how my function currently looks: function parseISO8601(s) { x = "2011-01-28T19:30:00-05:00" MM = {Jan:"January", Feb:"February", Mar:"March", Apr:"April", May:"May", Jun:"June", Jul:"July", Aug:"August", Sep:"September", Oct:"October", Nov:"November", Dec:"December"} xx = String(new Date(x)).replace( /\w{3} (\w{3}) (\d{2}) (\d{4}) (\d{2}):(\d{2}):[^(]+\\(([A-Z]{3})\\)/, function($0,$1,$2,$3,$4,$5,$6){ return MM[$1]+" "+$2+", "+$3+" - "+$4%12+":"+$5+(+$4>12?"PM":"AM")+" "+$6 } ) } – Slythic Jan 28 '11 at 17:12
  • @Slythic, could u do `alert(String(new Date("2011-01-28T19:30:00-05:00")))` in your script? and let me know the output? – YOU Jan 28 '11 at 17:14
  • S.Mark: UPDATE!! I only get 'Invalid Date' in Safari... Firefox seems to work fine! – Slythic Jan 28 '11 at 17:33
  • I see @Slythic, probably, might need to manually parse as your link. Problem now is I don't understand well those calculations. – YOU Jan 28 '11 at 17:39
  • Thanks for all your hard work. Just wish it would work as I had in mind. Thanks again! – Slythic Jan 31 '11 at 14:50
  • Safari does not support passing an ISO date to the Date constructor. Go figure. – Dale Anderson Jul 02 '12 at 06:44
24

If you want to keep it simple, this should suffice:

function parseIsoDatetime(dtstr) {
    var dt = dtstr.split(/[: T-]/).map(parseFloat);
    return new Date(dt[0], dt[1] - 1, dt[2], dt[3] || 0, dt[4] || 0, dt[5] || 0, 0);
}

note parseFloat is must, parseInt doesn't always work. Map requires IE9 or later.

Works for formats:

  • 2014-12-28 15:30:30
  • 2014-12-28T15:30:30
  • 2014-12-28

Not valid for timezones, see other answers about those.

Ciantic
  • 6,064
  • 4
  • 54
  • 49
  • 6
    +1 simple and portable. I made this change to interpret dates as UTC: `return new Date(Date.UTC(dt[0], dt[1] - 1, dt[2], dt[3] || 0, dt[4] || 0, dt[5] || 0, 0));` – Chris Olsen Sep 11 '16 at 13:00
  • 1
    Very nice little function that handles the most important part: fixing that dang month index. – Seth Aug 30 '18 at 19:20
  • Sigh, IE11 Enterprise (basically IE8) doesn't support map. Groan – Nathan Sep 08 '21 at 00:20
  • Found a polyfill and it's all working for IE8 too (just change .map to .myMap): `Array.prototype.myMap = function(callbackFn) { var arr = []; for (var i = 0; i < this.length; i++) { arr.push(callbackFn(this[i], i, this)); } return arr; }` – Nathan Sep 08 '21 at 00:26
  • To get the timezone with this approach, you can take the return of the above function (call it "d"), and run it through `toLocaleTimeString()`: `d.toLocaleTimeString([], { month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric', timeZone: 'America/Chicago', timeZoneName: 'short' })` This converts the date string `2022-10-03T14:43:51.000000Z`> to `October 3, 2022 at 2:43 PM CDT` – buckthorn Nov 08 '22 at 02:58
4

Maybe, you can use moment.js which in my opinion is the best JavaScript library for parsing, formatting and working with dates client-side. You could use something like:

var momentDate = moment('1890-09-30T23:59:59+01:16:20', 'YYYY-MM-DDTHH:mm:ss+-HH:mm:ss');
var jsDate = momentDate.toDate();

// Now, you can run any JavaScript Date method

jsDate.toLocaleString();

The advantage of using a library like moment.js is that your code will work perfectly even in legacy browsers like IE 8+.

Here is the documenation about parsing methods: https://momentjs.com/docs/#/parsing/

alex-arriaga
  • 117
  • 7
  • 1
    Moment is now in [legacy mode](https://momentjs.com/docs/#/-project-status/) and has been replaced by [luxon](https://moment.github.io/luxon/#/) and/or standard JS – Liam Feb 11 '22 at 09:40
-1

According to MSDN, the JavaScript Date object does not provide any specific date formatting methods (as you may see with other programming languages). However, you can use a few of the Date methods and formatting to accomplish your goal:

function dateToString (date) {
  // Use an array to format the month numbers
  var months = [
    "January",
    "February",
    "March",
    ...
  ];

  // Use an object to format the timezone identifiers
  var timeZones = {
    "360": "EST",
    ...
  };

  var month = months[date.getMonth()];
  var day = date.getDate();
  var year = date.getFullYear();

  var hours = date.getHours();
  var minutes = date.getMinutes();
  var time = (hours > 11 ? (hours - 11) : (hours + 1)) + ":" + minutes + (hours > 11 ? "PM" : "AM");
  var timezone = timeZones[date.getTimezoneOffset()];

  // Returns formatted date as string (e.g. January 28, 2011 - 7:30PM EST)
  return month + " " + day + ", " + year + " - " + time + " " + timezone;
}

var date = new Date("2011-01-28T19:30:00-05:00");

alert(dateToString(date));

You could even take it one step further and override the Date.toString() method:

function dateToString () { // No date argument this time
  // Use an array to format the month numbers
  var months = [
    "January",
    "February",
    "March",
    ...
  ];

  // Use an object to format the timezone identifiers
  var timeZones = {
    "360": "EST",
    ...
  };

  var month = months[*this*.getMonth()];
  var day = *this*.getDate();
  var year = *this*.getFullYear();

  var hours = *this*.getHours();
  var minutes = *this*.getMinutes();
  var time = (hours > 11 ? (hours - 11) : (hours + 1)) + ":" + minutes + (hours > 11 ? "PM" : "AM");
  var timezone = timeZones[*this*.getTimezoneOffset()];

  // Returns formatted date as string (e.g. January 28, 2011 - 7:30PM EST)
  return month + " " + day + ", " + year + " - " + time + " " + timezone;
}

var date = new Date("2011-01-28T19:30:00-05:00");
Date.prototype.toString = dateToString;

alert(date.toString());
Ryan V
  • 480
  • 3
  • 13