40

I have a ISO date string as below

 var startTimeISOString = "2013-03-10T02:00:00Z";

when I convert it to date object in javascript using below code, it returns

var startTimeDate = new Date(startTimeISOString);

output is

Date {Sun Mar 10 2013 07:30:00 GMT+0530 (India Standard Time)}

It sure converts the ISOString to date but it converts to local time since new Date() is client dependent. How to just convert iso date time string to date and time but not to local date-time..?

Thanks

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
CrazyNooB
  • 1,553
  • 3
  • 17
  • 23
  • 2
    Your ISO time ends with 'Z' which means UTC (GMT). If the time is in fact local to start with you should replace the 'Z' with '+0530'. But if you want to round trip your times you should keep the string version in UTC. – Randall Bohn Apr 11 '14 at 15:58
  • can you clarify that you are attempting to create a string representation that preserves the original timezone, in this case Zulu (Z), rather than re-interpreting the time in the timezone of the computer running the code. It sounds like you are, but it's not 100% clear. – Ed Sykes Jul 10 '15 at 08:00

6 Answers6

64

According to MDN:

Differences in assumed time zone

Given a date string of "March 7, 2014", parse() assumes a local time zone, but given an ISO format such as "2014-03-07" it will assume a time zone of UTC. Therefore Date objects produced using those strings will represent different moments in time unless the system is set with a local time zone of UTC. This means that two date strings that appear equivalent may result in two different values depending on the format of the string that is being converted (this behavior is changed in ECMAScript ed 6 so that both will be treated as local).

I have done like this and am now getting the exact time which is inside the ISO date string instead of the local time

 var startTimeISOString = "2013-03-10T02:00:00Z";

 var startTime = new Date(startTimeISOString );
 startTime =   new Date( startTime.getTime() + ( startTime.getTimezoneOffset() * 60000 ) );

This will give the same date time inside iso date string , the output here is

o/p

Date {Sun Mar 10 2013 02:00:00 GMT+0530 (India Standard Time)}
Jeremy Danyow
  • 26,470
  • 12
  • 87
  • 133
CrazyNooB
  • 1,553
  • 3
  • 17
  • 23
  • i don't see that the details of the parse function has anything to do with this. The quoted MDN paragraph just states that parse looks at the format of the string and figures out whether the format is RFC2822 or ISO8601. – Ed Sykes Jul 10 '15 at 08:05
  • The answer here gives the correct hour of the day, but it's dangerous because you're still in a different timezone to the original time. The correct answer would create a date object with the same timezone as the original. – Ed Sykes Jul 10 '15 at 08:11
  • Note that getTimezoneOffset is the difference between UTC and local, yielding the opposite of what one might expect. From MDN: " Note that this means that the offset is positive if the local timezone is behind UTC and negative if it is ahead. For example, if your time zone is UTC+10 (Australian Eastern Standard Time), -600 will be returned. " – Ed Sykes Jul 10 '15 at 08:19
  • I'm just reading the title of this question and this, the acceptance answer, doesn't answer the question - because it definitely doesn't assume the timezone of startTimeISOString. – Ed Sykes Jul 10 '15 at 08:26
  • @EdSykes—also, EMA-262 ed 6 (the current standard) changes parsing of ISO string without a timezone to be local rather than UTC (per ES5), so 2014-03-07 will be local in some browsers and UTC in others (and *NaN* in the rest). – RobG Jul 10 '15 at 08:40
  • 1
    If you insist on using the built-in parser, all you need to do is remove the trailing Z: `new Date(startTimeISOString.replace(/Z/,''))`. Note that an "ISO string" is not necessarily Z, and by adjusting it by the host timezone offset it represents a different moment in time from the original where the host offset is not +0000. – RobG Aug 18 '17 at 00:17
16

To sum up the conversation from tracevipin's post:

All Date objects are based on a time value that is milliseconds since 1970-01-01T00:00:00Z so they are UTC at their core. This is different to UNIX, which uses a value that is represents seconds since the same epoch.

The Date.prototype.toString method returns an implementation dependent string that represents the time based on the system settings and timezone offset of the client (aka local time).

If a UTC ISO8601 time string is required, the Date.prototype.toISOString method can be used. It's quite easy to write a "shim" for this methods if required.

Lastly, do not trust Date.parse to parse a string. Support for an ISO8601 format UTC string is specified in ES5, however it's not consistently implemented across browsers in use. It is much better to parse the string manually (it's not hard, there are examples on SO of how to do it) if wide browser support is required (e.g. typical web application).

Simple ISO8601 UTC time stamp parser:

function dateObjectFromUTC(s) {
  s = s.split(/\D/);
  return new Date(Date.UTC(+s[0], --s[1], +s[2], +s[3], +s[4], +s[5], 0));
}

and here's a shim for toISOString:

if (typeof Date.prototype.toISOString != 'function') {

  Date.prototype.toISOString = (function() {
  
    function z(n){return (n<10? '0' : '') + n;}
    function p(n){
      n = n < 10? z(n) : n;
      return n < 100? z(n) : n;
    }
    
    return function() {
      return this.getUTCFullYear() + '-' +
             z(this.getUTCMonth() + 1) + '-' +
             z(this.getUTCDate()) + 'T' +
             z(this.getUTCHours()) + ':' +
             z(this.getUTCMinutes()) + ':' +
             z(this.getUTCSeconds()) + '.' +
             p(this.getUTCMilliseconds()) + 'Z';
    } 
  }());
}
Nate Anderson
  • 18,334
  • 18
  • 100
  • 135
RobG
  • 142,382
  • 31
  • 172
  • 209
  • You should change your regex to `/[\-\.\+: TZ]/g` – Onur Yıldırım Feb 23 '14 at 22:57
  • @OnurYıldırım—you're right, it doesn't correctly split the string, the simplest RegExp to use is `/\D/`. It's not intended as a general ISO 8601 string parser, that is a very much bigger job. – RobG Feb 23 '14 at 23:44
  • ISO strings and UTC are two different things. This will not produce an ISO 8601 string. ISO 8601 encodes the timezone, this won't (due to use of getUTC...) – Ed Sykes Jul 10 '15 at 08:14
  • @EdSykes—I am well aware of that. There are many forms of ISO 8601 date and time strings that do not include a time zone, e.g. 2015-07, 2006-W52-5. This is a shim for ECMAScript's [*Date.prototype.toISOString*](http://ecma-international.org/ecma-262/6.0/index.html#sec-date.prototype.toisostring), which is UTC, so this shim is also UTC. – RobG Jul 10 '15 at 08:36
7

This happens because date is printed using toString method which by default returns the date and time in local timezone. The method toUTCString will give you the string you need.

Date actually keeps the date as unix time in milliseconds and provides methods to manipulate it.

Diode
  • 24,570
  • 8
  • 40
  • 51
  • can I have it as date object not a string? right now it returns a string, but I need it to be a date object since I am doing date comparisons with other date – CrazyNooB Mar 20 '13 at 07:14
  • As the date object stores unix time you can use the UTC methods wherever needed. See the UTC methods in Date : https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date – Diode Mar 20 '13 at 07:16
  • getUTCDate, getUTCMonth etc. – Diode Mar 20 '13 at 07:17
  • i get that, but can there be no direct conversion of iso date string to its correct date instead of local time in javascript..? – CrazyNooB Mar 20 '13 at 07:20
  • when we give a an iso date string, a Date object is created with its equivalent unix time. So the Date object is independent of timezone. Then methods like getDate, getMonth , toString etc. returns values of local time and methods like getUTCDate, getUTCMonth, toUTCString returns UTC values. You cannot specify timezone. If you need that kind of functionality either you have build it on Date or use a library like http://momentjs.com/ or https://github.com/mde/timezone-js – Diode Mar 20 '13 at 08:09
0

In vanilla javascript there isn't a way to create a date that assumes the local time of the ISO formatted string you give it. Here's what happens when you pass an ISO 8601 formatted string to javascript. I'm going to use a non UTC time as it illustrates the problem better than using an ISO formatted string:

  1. var startTime = new Date("2013-03-10T02:00:00+06:00"). Note this could also be 2013-03-10T02:00:00Z or any other ISO-formatted string.
  2. read the time, apply the offset and calculate milliseconds since 1970-01-01T00:00:00Z
  3. You now have only milliseconds - you have lost all timezone info. In this case 1362859200000

All functions, apart from the ones that give you a UTC representation of that number, will use the timezone of the computer running the code to interpret that number as a time.

To do what the original poster wants, you need to.

  1. parse the ISO string, interpret the offset ('Z' or '+06:00') as the timezone offset
  2. store the timezone offset
  3. calculate and store the ms since epoch, using the offset timezone offset
  4. hold that offset
  5. whenever attempting to make a calculation or print the date, apply the timezone offset.

This isn't trivial, and requires a complete interpretation of the 8601 spec. Way too much code to put here.

This is exactly what moment.js is designed to do. I strongly recommend using it. Using moment.js:

moment("2013-03-10T02:00:00Z").format()
"2013-03-10T02:00:00Z"

this will result in printing the ISO time of the original string, preserving the offset.

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
Ed Sykes
  • 1,399
  • 11
  • 18
0

you can try moment js library https://momentjs.com

For my case, I had 2022-10-17T01:00:00 on my database. SO I need to format it to the 01:00:00 AM.

So here was my solution.

var date = "2022-10-17T01:00:00"
var timeFormat = moment(date ).format('HH:mm A');

output: 01:00:00 AM

Pri Nce
  • 576
  • 6
  • 18
-2

it will return ISOdate

var getDate = () => {
    var dt = new Date();
    var off = dt.getTimezoneOffset() * 60000
    var newdt = new Date(dt - off).toISOString()
    return newdt.slice(0, 19)
}

Output enter image description here

George
  • 2,842
  • 2
  • 15
  • 11