[javascript] How to ISO 8601 format a Date with Timezone Offset in JavaScript?

Goal: Find the local time and UTC time offset then construct the URL in following format.

Example URL: /Actions/Sleep?duration=2002-10-10T12:00:00-05:00

The format is based on the W3C recommendation: http://www.w3.org/TR/xmlschema11-2/#dateTime

The documentation says:

For example, 2002-10-10T12:00:00-05:00 (noon on 10 October 2002, Central Daylight Savings Time as well as Eastern Standard Time in the U.S.) is equal to 2002-10-10T17:00:00Z, five hours later than 2002-10-10T12:00:00Z.

So based on my understanding, I need to find my local time by new Date() then use getTimezoneOffset() function to compute the difference then attach it to the end of string.

1.Get local time with format

var local = new Date().format("yyyy-MM-ddThh:mm:ss"); //today (local time)

output

2013-07-02T09:00:00

2.Get UTC time offset by hour

var offset = local.getTimezoneOffset() / 60;

output

7

3.Construct URL (time part only)

var duration = local + "-" + offset + ":00";

output:

2013-07-02T09:00:00-7:00

The above output means my local time is 2013/07/02 9am and difference from UTC is 7 hours (UTC is 7 hours ahead of local time)

So far it seems to work but what if getTimezoneOffset() returns negative value like -120?

I'm wondering how the format should look like in such case because I cannot figure out from W3C document. Thanks in advance.

This question is related to javascript timezone date-formatting

The answer is


My answer is a slight variation for those who just want today's date in the local timezone in the YYYY-MM-DD format.

Let me be clear:

My Goal: get today's date in the user's timezone but formatted as ISO8601 (YYYY-MM-DD)

Here is the code:

new Date().toLocaleDateString("sv") // "2020-02-23" // 

This works because the Sweden locale uses the ISO 8601 format.


This is my function for the clients timezone, it's lite weight and simple

  function getCurrentDateTimeMySql() {        
      var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
      var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, 19).replace('T', ' ');
      var mySqlDT = localISOTime;
      return mySqlDT;
  }

I think it is worth considering that you can get the requested info with just a single API call to the standard library...

new Date().toLocaleString( 'sv', { timeZoneName: 'short' } );

// produces "2019-10-30 15:33:47 GMT-4"

You would have to do text swapping if you want to add the 'T' delimiter, remove the 'GMT-', or append the ':00' to the end.

But then you can easily play with the other options if you want to eg. use 12h time or omit the seconds etc.

Note that I'm using Sweden as locale because it is one of the countries that uses ISO 8601 format. I think most of the ISO countries use this 'GMT-4' format for the timezone offset other then Canada which uses the time zone abbreviation eg. "EDT" for eastern-daylight-time.

You can get the same thing from the newer standard i18n function "Intl.DateTimeFormat()" but you have to tell it to include the time via the options or it will just give date.


Here are the functions I used for this end:

function localToGMTStingTime(localTime = null) {
    var date = localTime ? new Date(localTime) : new Date();
    return new Date(date.getTime() + (date.getTimezoneOffset() * 60000)).toISOString();
};

function GMTToLocalStingTime(GMTTime = null) {
    var date = GMTTime ? new Date(GMTTime) : new Date();;
    return new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString();
};

function setDate(){
    var now = new Date();
    now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
    var timeToSet = now.toISOString().slice(0,16);

    /*
        If you have an element called "eventDate" like the following:

        <input type="datetime-local" name="eventdate" id="eventdate" />

        and you would like to  set the current and minimum time then use the following:
    */

    var elem = document.getElementById("eventDate");
    elem.value = timeToSet;
    elem.min = timeToSet;
}

No moment.js needed: Here's a full round trip answer, from an input type of "datetime-local" which outputs an ISOLocal string to UTCseconds at GMT and back:

<input type="datetime-local" value="2020-02-16T19:30">

isoLocal="2020-02-16T19:30"
utcSeconds=new Date(isoLocal).getTime()/1000

//here you have 1581899400 for utcSeconds

let isoLocal=new Date(utcSeconds*1000-new Date().getTimezoneOffset()*60000).toISOString().substring(0,16)
2020-02-16T19:30

You can achieve this with a few simple extension methods. The following Date extension method returns just the timezone component in ISO format, then you can define another for the date/time part and combine them for a complete date-time-offset string.

Date.prototype.getISOTimezoneOffset = function () {
    const offset = this.getTimezoneOffset();
    return (offset < 0 ? "+" : "-") + Math.floor(Math.abs(offset / 60)).leftPad(2) + ":" + (Math.abs(offset % 60)).leftPad(2);
}

Date.prototype.toISOLocaleString = function () {
    return this.getFullYear() + "-" + (this.getMonth() + 1).leftPad(2) + "-" +
        this.getDate().leftPad(2) + "T" + this.getHours().leftPad(2) + ":" +
        this.getMinutes().leftPad(2) + ":" + this.getSeconds().leftPad(2) + "." +
        this.getMilliseconds().leftPad(3);
}

Number.prototype.leftPad = function (size) {
    var s = String(this);
    while (s.length < (size || 2)) {
        s = "0" + s;
    }
    return s;
}

Example usage:

var date = new Date();
console.log(date.toISOLocaleString() + date.getISOTimezoneOffset());
// Prints "2020-08-05T16:15:46.525+10:00"

I know it's 2020 and most people are probably using Moment.js by now, but a simple copy & pastable solution is still sometimes handy to have.

(The reason I split the date/time and offset methods is because I'm using an old Datejs library which already provides a flexible toString method with custom format specifiers, but just doesn't include the timezone offset. Hence, I added toISOLocaleString for anyone without said library.)


Just my two sends here

I was facing this issue with datetimes so what I did is this:

const moment = require('moment-timezone')

const date = moment.tz('America/Bogota').format()

Then save date to db to be able to compare it from some query.


To install moment-timezone

npm i moment-timezone

Check this:

function dateToLocalISO(date) {
    const off    = date.getTimezoneOffset()
    const absoff = Math.abs(off)
    return (new Date(date.getTime() - off*60*1000).toISOString().substr(0,23) +
            (off > 0 ? '-' : '+') + 
            (absoff / 60).toFixed(0).padStart(2,'0') + ':' + 
            (absoff % 60).toString().padStart(2,'0'))
}

// Test it:
d = new Date()

dateToLocalISO(d)
// ==> '2019-06-21T16:07:22.181-03:00'

// Is similar to:

moment = require('moment')
moment(d).format('YYYY-MM-DDTHH:mm:ss.SSSZ') 
// ==> '2019-06-21T16:07:22.181-03:00'

getTimezoneOffset() returns the opposite sign of the format required by the spec that you referenced.

This format is also known as ISO8601, or more precisely as RFC3339.

In this format, UTC is represented with a Z while all other formats are represented by an offset from UTC. The meaning is the same as JavaScript's, but the order of subtraction is inverted, so the result carries the opposite sign.

Also, there is no method on the native Date object called format, so your function in #1 will fail unless you are using a library to achieve this. Refer to this documentation.

If you are seeking a library that can work with this format directly, I recommend trying moment.js. In fact, this is the default format, so you can simply do this:

var m = moment();    // get "now" as a moment
var s = m.format();  // the ISO format is the default so no parameters are needed

// sample output:   2013-07-01T17:55:13-07:00

This is a well-tested, cross-browser solution, and has many other useful features.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to timezone

How to set the timezone in Django? How to convert Moment.js date to users local timezone? What does this format means T00:00:00.000Z? How do I get the current timezone name in Postgres 9.3? MySQL JDBC Driver 5.1.33 - Time Zone Issue Python get current time in right timezone Symfony2 and date_default_timezone_get() - It is not safe to rely on the system's timezone settings PHP date() with timezone? How to store a datetime in MySQL with timezone info Java SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") gives timezone as IST

Examples related to date-formatting

How to insert date values into table How do I format a date as ISO 8601 in moment.js? Java Convert GMT/UTC to Local time doesn't work as expected Compare two date formats in javascript/jquery How to ISO 8601 format a Date with Timezone Offset in JavaScript? What are the "standard unambiguous date" formats for string-to-date conversion in R? How to convert date in to yyyy-MM-dd Format? Convert timestamp to date in MySQL query Date formatting in WPF datagrid Return date as ddmmyyyy in SQL Server