241

I am trying to convert Twitter datetime to a local iso-string (for prettyDate) now for 2 days. I'm just not getting the local time right..

im using the following function:

function getLocalISOTime(twDate) {
    var d = new Date(twDate);
    var utcd = Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(),
        d.getMinutes(), d.getSeconds(), d.getMilliseconds());

    // obtain local UTC offset and convert to msec
    localOffset = d.getTimezoneOffset() * 60000;
    var newdate = new Date(utcd + localOffset);
    return newdate.toISOString().replace(".000", "");
}

in newdate everything is ok but the toISOString() throws it back to the original time again... Can anybody help me get the local time in iso from the Twitterdate formatted as: Thu, 31 May 2012 08:33:41 +0000

Cyril Mestrom
  • 6,042
  • 4
  • 19
  • 27
  • 2
    The format you describe at the end is not the [ISO-8601E](http://dotat.at/tmp/ISO_8601-2004_E.pdf) format (see also [Date.toISOString](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/toISOString). You can achieve the format you want quite easily; it's very close to what you get with `dateObj.toString()`. Try playing with that. – Zirak May 31 '12 at 09:18
  • Thanks! Ended up with this: var d = new Date(twDate); return new Date(d.toISOString().replace("Z", "-02:00")).toISOString().replace(".000", ""); Not the prettiest solution but works for my timezone. – Cyril Mestrom May 31 '12 at 09:26
  • 9
    @Bergi : Paradoxically, an older question cannot be a duplicate of a newer one ;) – JFK Sep 18 '15 at 23:13
  • Here is a method without any manual timezone settings: var now = new Date(); now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); var timeToSet = now.toISOString().slice(0,16); var elem = document.getElementById("eventdate"); elem.value = timeToSet; elem.min = timeToSet; – Ranch Camal Oct 26 '20 at 06:57

7 Answers7

434

moment.js is great but sometimes you don't want to pull a large number of dependencies for simple things.

The following works as well:

    var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
    var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1);
    
    console.log(localISOTime)  // => '2015-01-26T06:40:36.181'

The slice(0, -1) gets rid of the trailing Z which represents Zulu timezone and can be replaced by your own.

mplungjan
  • 169,008
  • 28
  • 173
  • 236
yegodz
  • 5,031
  • 2
  • 17
  • 18
  • 12
    short and simple - brilliant! To make it even more human readable I put .toISOString().slice(0,-5).replace("T", " "); at the end of your solution. – DerWOK Apr 07 '15 at 18:14
  • 9
    Times are expressed in UTC (Coordinated Universal Time), with a special UTC designator ("Z"). – N.K Nov 04 '15 at 11:22
  • 4
    Excellent, thanks. Here it is, as a function that takes an optional date parameter: function localISOTime(d) { if (!d) d = new Date() var tzoffset = d.getTimezoneOffset() * 60000; //offset in milliseconds return (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1); } – Nico May 22 '17 at 18:47
  • 1
    Why the "-" (now-tzoffset)? – haemse Jun 08 '17 at 23:48
  • 2
    @NicoDurand your function has a bug, it always returns the current Date. Should be "d - tzoffset" – pinoyyid Jul 01 '17 at 10:40
  • 2
    Your solution it does not show your local time. It trick the date thinking your UTC date is your local date. You should not change your date your should add your timezone offset – Mario Shtika Dec 20 '17 at 12:09
  • @MarioShtika We all know it is tricky because `Date` object doesn't provide a `toLocalISOString`. Then what's the correct way? Show us. – InQβ Oct 18 '19 at 04:38
  • See this answer for a more detailed explanation of each operation: https://stackoverflow.com/a/51643788/1412157 – LucaM Nov 07 '19 at 10:27
  • Is this guaranteed to be correct for all space and time? – Mateen Ulhaq May 16 '21 at 06:31
  • 1
    Be careful using `.getTimezoneOffset()`, whatever date you provide (from different timezones) it will always resolve to your local timezone offset. Example: `const date1 = new Date('August 19, 1975 23:15:30 GMT+07:00');` `const date2 = new Date('August 19, 1975 23:15:30 GMT-02:00');` `console.log(date1.getTimezoneOffset() === date2.getTimezoneOffset()); // true` [source MDN:](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset#description) – mehdi Ichkarrane Jul 09 '22 at 15:29
164

My solution without using moment is to convert it to a timestamp, add the timezone offset, then convert back to a date object, and then run the toISOString()

var date = new Date(); // Or the date you'd like converted.
var isoDateTime = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString();
Dustin Silk
  • 4,320
  • 5
  • 32
  • 48
  • 2
    I like this approach. You example doesn't work as-is because you haven't defined date. If you prepend var date = new Date(); to your example, it works. – Brady Holt Nov 30 '17 at 19:24
  • 2
    it works! but I don't understand why you multiply by 60000 ? :s – betoharres Feb 07 '19 at 03:49
  • 1
    Beautiful and very simple. Thank you. Just a note: it does keep "Z" at the end of the string, which is technically wrong, but easy to edit out. – Steve Gon Feb 07 '19 at 19:22
  • 3
    @betoharres that is to transform the time zone offset to milliseconds, which is what getTime is in. – Dustin Silk Feb 08 '19 at 11:50
  • @Dustin Silk so the solution proposed by you convert the datetime in local iso. Is there any way using which I can show the same date whether the user opens the app in usa, Europe or for say India. I am really struggling with it. Any help would be really appreciated – Varun May 07 '19 at 14:31
  • Your solution gives me `2020-01-17T11:24:15.109Z`. I like this approach better https://stackoverflow.com/a/17415677/588759 which shows for me correct zone `2020-01-17T11:25:26+01:00` with this patch https://stackoverflow.com/questions/17415579/how-to-iso-8601-format-a-date-with-timezone-offset-in-javascript/17415677#comment78688226_17415677 – rofrol Jan 17 '20 at 10:25
13

moment.js FTW!!!

Just convert your date to a moment and manipulate it however you please:

var d = new Date(twDate);
var m = moment(d).format();
console.log(m);
// example output:
// 2016-01-08T00:00:00-06:00

http://momentjs.com/docs/

Nate Anderson
  • 18,334
  • 18
  • 100
  • 135
boxes
  • 227
  • 2
  • 5
  • 13
    That's not a proper answer... Can you give the right answer using Moment.js ? If that's a real answer, I can answer everytime "x86 FTW !!! https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf " and say good luck... – DestyNova Sep 06 '17 at 16:07
  • 4
    [*When is “use jQuery” not a valid answer to a JavaScript question?*](https://meta.stackoverflow.com/questions/335328/when-is-use-jquery-not-a-valid-answer-to-a-javascript-question) – RobG Jan 23 '18 at 05:18
  • I logged in after many years offline just to note that this answer allow to format Date in order for a .NET API to receive a date with the TimeZone and deserialize it properly. It's not that bad to have moment.js in a js project, knowing how much the Date API from ECMAScript lacks of functionalities. – Léon Pelletier Sep 23 '20 at 20:52
  • 1
    I logged in after many years offline just to note that the solution offered in the answer allows to serialize a local hour properly in ISO8601. moment.js exists because the Date API from ECMAScript sucks. – Léon Pelletier Sep 23 '20 at 20:54
12

Using moment.js, you can use keepOffset parameter of toISOString:

toISOString(keepOffset?: boolean): string;

moment().toISOString(true)

Arash Motamedi
  • 9,284
  • 5
  • 34
  • 43
Omer Gurarslan
  • 979
  • 11
  • 15
6

This date function below achieves the desired effect without an additional script library. Basically it's just a simple date component concatenation in the right format, and augmenting of the Date object's prototype.

 Date.prototype.dateToISO8601String  = function() {
    var padDigits = function padDigits(number, digits) {
        return Array(Math.max(digits - String(number).length + 1, 0)).join(0) + number;
    }
    var offsetMinutes = this.getTimezoneOffset();
    var offsetHours = offsetMinutes / 60;
    var offset= "Z";    
    if (offsetHours < 0)
      offset = "-" + padDigits(offsetHours.replace("-","") + "00",4);
    else if (offsetHours > 0) 
      offset = "+" + padDigits(offsetHours  + "00", 4);

    return this.getFullYear() 
            + "-" + padDigits((this.getUTCMonth()+1),2) 
            + "-" + padDigits(this.getUTCDate(),2) 
            + "T" 
            + padDigits(this.getUTCHours(),2)
            + ":" + padDigits(this.getUTCMinutes(),2)
            + ":" + padDigits(this.getUTCSeconds(),2)
            + "." + padDigits(this.getUTCMilliseconds(),2)
            + offset;

}

Date.dateFromISO8601 = function(isoDateString) {
      var parts = isoDateString.match(/\d+/g);
      var isoTime = Date.UTC(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]);
      var isoDate = new Date(isoTime);
      return isoDate;       
}

function test() {
    var dIn = new Date();
    var isoDateString = dIn.dateToISO8601String();
    var dOut = Date.dateFromISO8601(isoDateString);
    var dInStr = dIn.toUTCString();
    var dOutStr = dOut.toUTCString();
    console.log("Dates are equal: " + (dInStr == dOutStr));
}

Usage:

var d = new Date();
console.log(d.dateToISO8601String());

Hopefully this helps someone else.

EDIT

Corrected UTC issue mentioned in comments, and credit to Alex for the dateFromISO8601 function.

Community
  • 1
  • 1
James
  • 12,636
  • 12
  • 67
  • 104
  • this helped me and I think it is a better answer. – Jonathan Sep 22 '13 at 21:41
  • 2
    While you are getting the correct local time, you are incorrectly associating that time with zulu time by adding the "Z" in place of the timezone. If you were to take the time created from this and put it into any ISO conforming application, you would *not* get the correct time in return. You should call `.getTimezoneOffset()` and then calculate the minutes into an hours format in place of that in order for your ISO date to be conforming. – Kevin Peno Oct 18 '13 at 16:23
  • thats wrong and doesnt work Im afraid – Daij-Djan Apr 03 '14 at 14:21
  • And now you're getting the UTC values but combine them with the local timezone offset? – Bergi Apr 03 '14 at 19:06
  • The combination with the local timezone offset happens in the date object already. Here is a [jsfiddle](http://jsfiddle.net/83Ltp/1/) that illustrates that. If you just want a local string than just build that with the date parts in a concatenation. – James Apr 09 '14 at 04:46
  • @James I think you should put `.toString()` before `.replace` here `offsetHours.replace("-","") + "00"`. – ivkremer Nov 06 '14 at 10:55
  • 2
    As the code is currently, this does not output ISO8601 compliant strings and outputs incorrect times for all but those in UTC timezone. ISO8601 compliant offsets are in the form `+HH:MM` not `+HH00`. If you're going to use `+/-NN:NN` suffix for offset hours/minutes that your local timezone is from `Z`, you need to use local Month, Date, Hours, Minutes, Seconds, and Milliseconds instead of the UTC versions. This function should be called `Date.prototype.toLocalISOString` which is more inline with the standard `Date` functions. `dateFromISO8601` is unnecessary as `new Date()` works. – Cameron Tacklind Mar 06 '18 at 23:46
  • Too much bigger to a simple solution. – Luã Melo Jan 11 '19 at 12:43
  • This answer computes a UTC string with the timezone offset, which can be useful. However, it does not work for offsets that are not on the hour. – Adam Leggett Aug 06 '20 at 19:22
6

It will be very helpful to get current date and time.

var date=new Date();
  var today=new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().replace(/T/, ' ').replace(/\..+/, '');  
zaerymoghaddam
  • 3,037
  • 1
  • 27
  • 33
Nagnath Mungade
  • 921
  • 10
  • 11
-3

Moment js solution to this is

var d = new Date(new Date().setHours(0,0,0,0));
m.add(m.utcOffset(), 'm')
m.toDate().toISOString()
// output "2019-07-18T00:00:00.000Z"
Ravi Kumar Mistry
  • 1,063
  • 1
  • 13
  • 24