1

Why does this method use UTC timezone (Z) and not include the local time offset (+/-HH:SS) instead? The "ISO" in the method name refers to ISO 8601—which allows for "time zone designations" to be expressed as part of its format.

In other words, new Date() tells me both the date and time, and the timezone offset (via getTimezoneOffset()). But toISOString() only tells me the date and time in one timezone—it discards the information of what time it was in the locale that the new Date() originated.

Wouldn't it make sense for toISOString() to also include the originating timezone's offset from UTC? toISOString()'s omission of +/-HH:SS loses information about the originating Date if it's used for serializing.

All my AJAX calls (Angular, jQuery) serialize via toISOString(), thus losing the local time of the serialized date when it's communicated to the server. Any way to get a JavaScript Date to output an ISO-formatted string that also includes offset (besides using a library like Moment.js), or do I need to write my own method?

FOO
  • 592
  • 3
  • 14
  • not sure what the problem is... it will always convert back to the same exact time in your timezone using `Date` object – charlietfl Oct 08 '15 at 22:04

1 Answers1

4

This is one of those "because that's what the language specification says" answers (see ECMA-262 §20.3.4.36). ISO 8601 is a format, and while it allows the use of timezone data, ECMAScript only uses UTC. You can extend Date.prototype with your own toLocalISOString method if you wish. BTW, writing such a method is not difficult.

// Format date as ISO 8601 long format with local timezone offset
if (!Date.prototype.toLocalISOString) {
  Date.prototype.toLocalISOString = function() {
  
  // Helper for padding
  function pad(n, len) {
    return ('000' + n).slice(-len);
  }

  // If not called on a Date instance, or timevalue is NaN, return undefined
  if (isNaN(this) || Object.prototype.toString.call(this) != '[object Date]') return;

  // Otherwise, return an ISO format string with the current system timezone offset
  var d = this;
  var os = d.getTimezoneOffset();
  var sign = (os > 0? '-' : '+');
  os = Math.abs(os);

  return pad(d.getFullYear(), 4) + '-' +
         pad(d.getMonth() + 1, 2) + '-' +
         pad(d.getDate(), 2) +
         'T' + 
         pad(d.getHours(), 2) + ':' +
         pad(d.getMinutes(), 2) + ':' +
         pad(d.getSeconds(), 2) + '.' +
         pad(d.getMilliseconds(), 3) + 
       
         // Note sign of ECMASCript offsets are opposite to ISO 8601
         sign +
         pad(os/60 | 0, 2) + ':' +
         pad(os%60, 2);
  }
}
document.write(new Date().toLocalISOString())

Edit

Based on a post by DanDascalescu, here's an alternative that might be more efficient as it has fewer function calls, but it creates two additional Date objects:

// Return a string in ISO 8601 extended format with the host timezone offset
Date.prototype.toLocalISOString = function() {

    // If not called on a Date instance, or timevalue is NaN, return undefined
    if (isNaN(this) || Object.prototype.toString.call(this) != '[object Date]') return;

    // Copy date so don't modify original
    var d = new Date(+this);
    var offset = d.getTimezoneOffset();
    var offSign = offset > 0? '-' : '+';
    offset = Math.abs(offset);
    var tz = offSign + ('0' + (offset/60|0)).slice(-2) + ':' + ('0' + offset%60).slice(-2)
    return new Date(d.setMinutes(d.getMinutes() - d.getTimezoneOffset())).toISOString().slice(0,-1) + tz; 
}

console.log(new Date().toLocalISOString())
Community
  • 1
  • 1
RobG
  • 124,520
  • 28
  • 153
  • 188
  • @JuanMendes—this doesn't break any existing behaviour, it adds a new method. Admittedly there's the possibility of a name clash with some future version of ECMAScript, but since most of the date formatting has been handed to [*ECMA-402*](http://www.ecma-international.org/publications/standards/Ecma-402.htm), hopefully similar functionality wont be added to *Date.prototype*. – RobG Oct 09 '15 at 01:50
  • @DanDascalescu—that is **not** the same thing. All the "simpler way" does is trim the time zone from a UTC date and time so that it also loses its absolute reference. It becomes a different moment in time zones with different offsets. This answer includes the host time zone offset, so it keeps it's absolute reference. – RobG Sep 14 '16 at 02:15