How to pass datetime from client(browser) to server [duplicate] - 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. 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.
Get local time with format
var local = new Date().format("yyyy-MM-ddThh:mm:ss"); // 2013-07-02T09:00:00
Get UTC time offset by hour
var offset = local.getTimezoneOffset() / 60; // 7
Construct URL (time part only)
var duration = local + "-" + offset + ":00"; // 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 documentation.

Here's a simple helper function that will format JS dates for you.
function toIsoString(date) {
var tzo = -date.getTimezoneOffset(),
dif = tzo >= 0 ? '+' : '-',
pad = function(num) {
return (num < 10 ? '0' : '') + num;
};
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
dif + pad(Math.floor(Math.abs(tzo) / 60)) +
':' + pad(Math.abs(tzo) % 60);
}
var dt = new Date();
console.log(toIsoString(dt));

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.

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.

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;
}

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 ? '-' : '+') +
Math.floor(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'

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 cents 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

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

date to ISO string,
with local(computer) time zone,
with or without milliseconds
ISO ref: https://en.wikipedia.org/wiki/ISO_8601
how to use: toIsoLocalTime(new Date())
function toIsoLocalTime(value) {
if (value instanceof Date === false)
value = new Date();
const off = value.getTimezoneOffset() * -1;
const del = value.getMilliseconds() ? 'Z' : '.'; // have milliseconds ?
value = new Date(value.getTime() + off * 60000); // add or subtract time zone
return value
.toISOString()
.split(del)[0]
+ (off < 0 ? '-' : '+')
+ ('0' + Math.abs(Math.floor(off / 60))).substr(-2)
+ ':'
+ ('0' + Math.abs(off % 60)).substr(-2);
}
function test(value) {
const event = new Date(value);
console.info(value + ' -> ' + toIsoLocalTime(event) + ', test = ' + (event.getTime() === (new Date(toIsoLocalTime(event))).getTime() ));
}
test('2017-06-14T10:00:00+03:00'); // test with timezone
test('2017-06-14T10:00:00'); // test with local timezone
test('2017-06-14T10:00:00Z'); // test with UTC format
test('2099-12-31T23:59:59.999Z'); // date with milliseconds
test((new Date()).toString()); // now

consider using moment (like Matt's answer).
From version 2.20.0, you may call .toISOString(true) to prevent UTC conversion:
console.log(moment().toISOString(true));
// sample output: 2022-04-06T16:26:36.758+03:00

Use Temporal.
Temporal.Now.zonedDateTimeISO().toString()
// '2022-08-09T14:16:47.762797591-07:00[America/Los_Angeles]'
To omit the fractional seconds and IANA time zone:
Temporal.Now.zonedDateTimeISO().toString({
timeZoneName: "never",
fractionalSecondDigits: 0
})
// '2022-08-09T14:18:34-07:00'
Note: Temporal is currently (2022) available as a polyfill, but will soon be available in major browsers.

With luxon:
DateTime.now().toISODate() // 2022-05-23

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();
};

let myDate = new Date(dateToBeFormatted * 1000); // depends if you have milliseconds, or seconds, then the * 1000 might be not, or required.
timeOffset = myDate.getTimezoneOffset();
myDate = new Date(myDate.getTime() - (timeOffset * 60 * 1000));
console.log(myDate.toISOString().split('T')[0]);
Inspired by https://stackoverflow.com/a/29774197/11127383, including timezone offset comment.

a simple way to get:
//using a sample date
let iso_str = '2022-06-11T01:51:59.618Z';
let d = new Date(iso_str);
let tz = 'America/Santiago'
let options = {
timeZone:tz ,
timeZoneName:'longOffset',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
fractionalSecondDigits: 3
}
str_locale = d.toLocaleString("sv-SE",options);
iso_str_tz = str_locale.replace(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2}),(\d+)\s+/,'$1-$2-$3T$4:$5:$6.$7').replace('GMT−', '-' ).replace('GMT+','+')
console.log('iso_str : ',iso_str);
console.log('str_locale : ',str_locale);
console.log('iso_str_tz : ',iso_str_tz);
console.log('iso_str_tz --> date : ',new Date(iso_str_tz));
console.log('iso_str_tz --> iso_str: ',new Date(iso_str_tz).toISOString());

Using moment.js, you can use keepOffset parameter of toISOString:
toISOString(keepOffset?: boolean): string;
moment().toISOString(true)

Alternative approach with dayjs
import dayjs from "dayjs"
const formattedDateTime = dayjs(new Date()).format()
console.log(formattedDateTime) // Prints 2022-11-09T07:49:29+03:00

Here's another way a convert your date with an offset.
function toCustomDateString(date, offset) {
function pad(number) {
if (number < 10) {
return "0" + number;
}
return number;
}
var offsetHours = offset / 60;
var offsetMinutes = offset % 60;
var sign = (offset > 0) ? "+" : "-";
offsetHours = pad(Math.floor(Math.abs(offsetHours)));
offsetMinutes = pad(Math.abs(offsetMinutes));
return date.getFullYear() +
"-" + pad(date.getMonth() + 1) +
"-" + pad(date.getDate()) +
"T" + pad(date.getHours()) +
":" + pad(date.getMinutes()) +
":" + pad(date.getSeconds()) +
sign + offsetHours +
":" + offsetMinutes;
}
Then you can use it like this:
var date = new Date();
var offset = 330; // offset in minutes from UTC, for India it is 330 minutes ahead of UTC
var customDateString = toCustomDateString(date, offset);
console.log(customDateString);
// Output: "2023-02-09T10:29:31+05:30"

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;
}

I found another more easy solution:
let now = new Date();
// correct time zone offset for generating iso string
now.setMinutes(now.getMinutes() - now.getTimezoneOffset())
now = now.toISOString();
I undo the timezone offset by substracting it from the current date object.
The UTC time from the date object is now pointing to the local time.
That gives you the possibility to get the iso date for the local time.

Related

JavaScript get this month's 1st date [duplicate]

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. 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.
Get local time with format
var local = new Date().format("yyyy-MM-ddThh:mm:ss"); // 2013-07-02T09:00:00
Get UTC time offset by hour
var offset = local.getTimezoneOffset() / 60; // 7
Construct URL (time part only)
var duration = local + "-" + offset + ":00"; // 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 documentation.
Here's a simple helper function that will format JS dates for you.
function toIsoString(date) {
var tzo = -date.getTimezoneOffset(),
dif = tzo >= 0 ? '+' : '-',
pad = function(num) {
return (num < 10 ? '0' : '') + num;
};
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
dif + pad(Math.floor(Math.abs(tzo) / 60)) +
':' + pad(Math.abs(tzo) % 60);
}
var dt = new Date();
console.log(toIsoString(dt));
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.
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.
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;
}
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 ? '-' : '+') +
Math.floor(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'
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 cents 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
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
date to ISO string,
with local(computer) time zone,
with or without milliseconds
ISO ref: https://en.wikipedia.org/wiki/ISO_8601
how to use: toIsoLocalTime(new Date())
function toIsoLocalTime(value) {
if (value instanceof Date === false)
value = new Date();
const off = value.getTimezoneOffset() * -1;
const del = value.getMilliseconds() ? 'Z' : '.'; // have milliseconds ?
value = new Date(value.getTime() + off * 60000); // add or subtract time zone
return value
.toISOString()
.split(del)[0]
+ (off < 0 ? '-' : '+')
+ ('0' + Math.abs(Math.floor(off / 60))).substr(-2)
+ ':'
+ ('0' + Math.abs(off % 60)).substr(-2);
}
function test(value) {
const event = new Date(value);
console.info(value + ' -> ' + toIsoLocalTime(event) + ', test = ' + (event.getTime() === (new Date(toIsoLocalTime(event))).getTime() ));
}
test('2017-06-14T10:00:00+03:00'); // test with timezone
test('2017-06-14T10:00:00'); // test with local timezone
test('2017-06-14T10:00:00Z'); // test with UTC format
test('2099-12-31T23:59:59.999Z'); // date with milliseconds
test((new Date()).toString()); // now
consider using moment (like Matt's answer).
From version 2.20.0, you may call .toISOString(true) to prevent UTC conversion:
console.log(moment().toISOString(true));
// sample output: 2022-04-06T16:26:36.758+03:00
Use Temporal.
Temporal.Now.zonedDateTimeISO().toString()
// '2022-08-09T14:16:47.762797591-07:00[America/Los_Angeles]'
To omit the fractional seconds and IANA time zone:
Temporal.Now.zonedDateTimeISO().toString({
timeZoneName: "never",
fractionalSecondDigits: 0
})
// '2022-08-09T14:18:34-07:00'
Note: Temporal is currently (2022) available as a polyfill, but will soon be available in major browsers.
With luxon:
DateTime.now().toISODate() // 2022-05-23
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();
};
let myDate = new Date(dateToBeFormatted * 1000); // depends if you have milliseconds, or seconds, then the * 1000 might be not, or required.
timeOffset = myDate.getTimezoneOffset();
myDate = new Date(myDate.getTime() - (timeOffset * 60 * 1000));
console.log(myDate.toISOString().split('T')[0]);
Inspired by https://stackoverflow.com/a/29774197/11127383, including timezone offset comment.
a simple way to get:
//using a sample date
let iso_str = '2022-06-11T01:51:59.618Z';
let d = new Date(iso_str);
let tz = 'America/Santiago'
let options = {
timeZone:tz ,
timeZoneName:'longOffset',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
fractionalSecondDigits: 3
}
str_locale = d.toLocaleString("sv-SE",options);
iso_str_tz = str_locale.replace(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2}),(\d+)\s+/,'$1-$2-$3T$4:$5:$6.$7').replace('GMT−', '-' ).replace('GMT+','+')
console.log('iso_str : ',iso_str);
console.log('str_locale : ',str_locale);
console.log('iso_str_tz : ',iso_str_tz);
console.log('iso_str_tz --> date : ',new Date(iso_str_tz));
console.log('iso_str_tz --> iso_str: ',new Date(iso_str_tz).toISOString());
Using moment.js, you can use keepOffset parameter of toISOString:
toISOString(keepOffset?: boolean): string;
moment().toISOString(true)
Alternative approach with dayjs
import dayjs from "dayjs"
const formattedDateTime = dayjs(new Date()).format()
console.log(formattedDateTime) // Prints 2022-11-09T07:49:29+03:00
Here's another way a convert your date with an offset.
function toCustomDateString(date, offset) {
function pad(number) {
if (number < 10) {
return "0" + number;
}
return number;
}
var offsetHours = offset / 60;
var offsetMinutes = offset % 60;
var sign = (offset > 0) ? "+" : "-";
offsetHours = pad(Math.floor(Math.abs(offsetHours)));
offsetMinutes = pad(Math.abs(offsetMinutes));
return date.getFullYear() +
"-" + pad(date.getMonth() + 1) +
"-" + pad(date.getDate()) +
"T" + pad(date.getHours()) +
":" + pad(date.getMinutes()) +
":" + pad(date.getSeconds()) +
sign + offsetHours +
":" + offsetMinutes;
}
Then you can use it like this:
var date = new Date();
var offset = 330; // offset in minutes from UTC, for India it is 330 minutes ahead of UTC
var customDateString = toCustomDateString(date, offset);
console.log(customDateString);
// Output: "2023-02-09T10:29:31+05:30"
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;
}
I found another more easy solution:
let now = new Date();
// correct time zone offset for generating iso string
now.setMinutes(now.getMinutes() - now.getTimezoneOffset())
now = now.toISOString();
I undo the timezone offset by substracting it from the current date object.
The UTC time from the date object is now pointing to the local time.
That gives you the possibility to get the iso date for the local time.

Get the hour shown in an ISOstring with an offset [duplicate]

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. 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.
Get local time with format
var local = new Date().format("yyyy-MM-ddThh:mm:ss"); // 2013-07-02T09:00:00
Get UTC time offset by hour
var offset = local.getTimezoneOffset() / 60; // 7
Construct URL (time part only)
var duration = local + "-" + offset + ":00"; // 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 documentation.
Here's a simple helper function that will format JS dates for you.
function toIsoString(date) {
var tzo = -date.getTimezoneOffset(),
dif = tzo >= 0 ? '+' : '-',
pad = function(num) {
return (num < 10 ? '0' : '') + num;
};
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
dif + pad(Math.floor(Math.abs(tzo) / 60)) +
':' + pad(Math.abs(tzo) % 60);
}
var dt = new Date();
console.log(toIsoString(dt));
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.
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.
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;
}
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 ? '-' : '+') +
Math.floor(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'
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 cents 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
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
date to ISO string,
with local(computer) time zone,
with or without milliseconds
ISO ref: https://en.wikipedia.org/wiki/ISO_8601
how to use: toIsoLocalTime(new Date())
function toIsoLocalTime(value) {
if (value instanceof Date === false)
value = new Date();
const off = value.getTimezoneOffset() * -1;
const del = value.getMilliseconds() ? 'Z' : '.'; // have milliseconds ?
value = new Date(value.getTime() + off * 60000); // add or subtract time zone
return value
.toISOString()
.split(del)[0]
+ (off < 0 ? '-' : '+')
+ ('0' + Math.abs(Math.floor(off / 60))).substr(-2)
+ ':'
+ ('0' + Math.abs(off % 60)).substr(-2);
}
function test(value) {
const event = new Date(value);
console.info(value + ' -> ' + toIsoLocalTime(event) + ', test = ' + (event.getTime() === (new Date(toIsoLocalTime(event))).getTime() ));
}
test('2017-06-14T10:00:00+03:00'); // test with timezone
test('2017-06-14T10:00:00'); // test with local timezone
test('2017-06-14T10:00:00Z'); // test with UTC format
test('2099-12-31T23:59:59.999Z'); // date with milliseconds
test((new Date()).toString()); // now
consider using moment (like Matt's answer).
From version 2.20.0, you may call .toISOString(true) to prevent UTC conversion:
console.log(moment().toISOString(true));
// sample output: 2022-04-06T16:26:36.758+03:00
Use Temporal.
Temporal.Now.zonedDateTimeISO().toString()
// '2022-08-09T14:16:47.762797591-07:00[America/Los_Angeles]'
To omit the fractional seconds and IANA time zone:
Temporal.Now.zonedDateTimeISO().toString({
timeZoneName: "never",
fractionalSecondDigits: 0
})
// '2022-08-09T14:18:34-07:00'
Note: Temporal is currently (2022) available as a polyfill, but will soon be available in major browsers.
With luxon:
DateTime.now().toISODate() // 2022-05-23
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();
};
let myDate = new Date(dateToBeFormatted * 1000); // depends if you have milliseconds, or seconds, then the * 1000 might be not, or required.
timeOffset = myDate.getTimezoneOffset();
myDate = new Date(myDate.getTime() - (timeOffset * 60 * 1000));
console.log(myDate.toISOString().split('T')[0]);
Inspired by https://stackoverflow.com/a/29774197/11127383, including timezone offset comment.
a simple way to get:
//using a sample date
let iso_str = '2022-06-11T01:51:59.618Z';
let d = new Date(iso_str);
let tz = 'America/Santiago'
let options = {
timeZone:tz ,
timeZoneName:'longOffset',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
fractionalSecondDigits: 3
}
str_locale = d.toLocaleString("sv-SE",options);
iso_str_tz = str_locale.replace(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2}),(\d+)\s+/,'$1-$2-$3T$4:$5:$6.$7').replace('GMT−', '-' ).replace('GMT+','+')
console.log('iso_str : ',iso_str);
console.log('str_locale : ',str_locale);
console.log('iso_str_tz : ',iso_str_tz);
console.log('iso_str_tz --> date : ',new Date(iso_str_tz));
console.log('iso_str_tz --> iso_str: ',new Date(iso_str_tz).toISOString());
Using moment.js, you can use keepOffset parameter of toISOString:
toISOString(keepOffset?: boolean): string;
moment().toISOString(true)
Alternative approach with dayjs
import dayjs from "dayjs"
const formattedDateTime = dayjs(new Date()).format()
console.log(formattedDateTime) // Prints 2022-11-09T07:49:29+03:00
Here's another way a convert your date with an offset.
function toCustomDateString(date, offset) {
function pad(number) {
if (number < 10) {
return "0" + number;
}
return number;
}
var offsetHours = offset / 60;
var offsetMinutes = offset % 60;
var sign = (offset > 0) ? "+" : "-";
offsetHours = pad(Math.floor(Math.abs(offsetHours)));
offsetMinutes = pad(Math.abs(offsetMinutes));
return date.getFullYear() +
"-" + pad(date.getMonth() + 1) +
"-" + pad(date.getDate()) +
"T" + pad(date.getHours()) +
":" + pad(date.getMinutes()) +
":" + pad(date.getSeconds()) +
sign + offsetHours +
":" + offsetMinutes;
}
Then you can use it like this:
var date = new Date();
var offset = 330; // offset in minutes from UTC, for India it is 330 minutes ahead of UTC
var customDateString = toCustomDateString(date, offset);
console.log(customDateString);
// Output: "2023-02-09T10:29:31+05:30"
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;
}
I found another more easy solution:
let now = new Date();
// correct time zone offset for generating iso string
now.setMinutes(now.getMinutes() - now.getTimezoneOffset())
now = now.toISOString();
I undo the timezone offset by substracting it from the current date object.
The UTC time from the date object is now pointing to the local time.
That gives you the possibility to get the iso date for the local time.

How to convert current time to EST to ISO 8601 string format? [duplicate]

how do I format a javascript date like ISO format, but in local time?
with myDate.toISOString() I am getting the time as: "2012-09-13T19:12:23.826Z"
but here, it is 22:13, so how do I include the timezone in above format?
I ended up doing...
pad=function(e,t,n){n=n||"0",t=t||2;while((""+e).length<t)e=n+e;return e}
c = new Date()
c.getFullYear()+"-"+pad(c.getMonth()+1)+"-"+pad(c.getDate()-5)+"T"+c.toLocaleTimeString().replace(/\D/g,':')+"."+pad(c.getMilliseconds(),3)
No library required! For some Date object, e.g. t = new Date()
convert the local time zone offset from minutes to milliseconds
z = t.getTimezoneOffset() * 60 * 1000
subtract the offset from t
tLocal = t-z
create shifted Date object
tLocal = new Date(tLocal)
convert to ISO format string
iso = tLocal.toISOString()
drop the milliseconds and zone
iso = iso.split(".")[0]
replace the ugly 'T' with a space
iso = iso.replace('T', ' ')
Result is a nice ISO-ish format date-time string like "2018-08-01 22:45:50" in the local time zone.
A bit of a hack but can be done in one line by taking advantage of the fact that Sweden uses a format very close to ISO:
// Returns a string like 2021-01-17T01:59:57
function dateToISOButLocal(date) {
return date.toLocaleString('sv').replace(' ', 'T');
}
To support milliseconds:
return date.toLocaleString('sv', {year:'numeric', month:'numeric', day:'numeric', hour:'numeric', minute:'numeric', second:'numeric', fractionalSecondDigits: 3}).replace(',', '.').replace(' ', 'T');
I went with what Denis Howe said, below as a ready made function for convenience.
Also one fix: in the original answer t-z does not work because t is a Date, not milliseconds.
function dateToISOLikeButLocal(date) {
const offsetMs = date.getTimezoneOffset() * 60 * 1000;
const msLocal = date.getTime() - offsetMs;
const dateLocal = new Date(msLocal);
const iso = dateLocal.toISOString();
const isoLocal = iso.slice(0, 19);
return isoLocal;
}
With this I get the kind of string that needed as a URL parameter:
"2018-11-16T12:23:50"
AFAIK you can't format dates in javascript (without using external libraries). The best you could do is "format it yourself". I mean:
var date = new Date();
var year = date.getFullYear();
var month = date......
var ISOdate = year + "-" + month + "-" + .... ;
But there are some good libraries that will let you format dates! (read "format" as in library.getDate("YYYY-MM-DD.........");)
EDIT:
Moment.js seems the thing you're looking for: http://momentjs.com/
Although answers here might work, there's nothing like a simple one-liner:
new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60 * 1000).toISOString()
Explanation for those who are interested:
We create a new instance of Date (the outer one).
We give it another instance of Date (in milliseconds) from which we subtract the timezone offset (in milliseconds too, either positive or negative). All of this we format into ISO
I don't quite understand which date did you need
but I think you need
const ISOLocaleString = d => {
const pad = n => n < 10 ? '0'+n : n;
return d.getFullYear()+'-'
+ pad(d.getMonth()+1)+'-'
+ pad(d.getDate())+'T'
+ pad(d.getHours())+':'
+ pad(d.getMinutes())+':'
+ pad(d.getSeconds())+'Z'
}
or
const ISOUTCLocaleString = d => {
const pad = n => n<10 ? '0'+n : n;
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+'T'
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())+':'
+ pad(d.getUTCSeconds())+'Z'
}
In the original post, the current ISO date is "2012-09-13T19:12:23.826Z"
If what is wanted is a date that respects ISO norm but reflects the local offset from UTC time, the target answer should be "2012-09-13T22:12:23.826+03:00".
Best answer in the post bellow, with code snippet that respects the ISO 8601 format / RFC 3339
https://stackoverflow.com/a/17415677/1563072
Another method is to define a prototype on the Date object that leverages the built-in toISOString method (a separate function is also provided):
// Extend Date.prototype
Date.prototype.toLocalISOString = function() {
// Get the local offset for the date in minutes
let offsetMins = this.getTimezoneOffset();
// Get a time value adjusted for the offset
let localTimeMs = this - offsetMins * 6e4;
// Make a new Date so don't affect this
let date = new Date(localTimeMs);
// Get the local offset sign (ECMAScript sign is opposite to usual)
let utcOffsetSign = offsetMins > 0? '-' : '+';
// Remove sign from offsetMins
offsetMins = Math.abs(offsetMins);
// Get offset hours and minutes, padd to 2 digits
let utcOffsetHr = String(offsetMins / 60 | 0).padStart(2,'0');
let utcOffsetMin = String(offsetMins % 60).padStart(2,'0');
// Build offset string
let utcOffsetString = `${utcOffsetSign}${utcOffsetHr}:${utcOffsetMin}`;
// Return as adjusted ISO 8601 format string with adjusted offset
return date.toISOString().replace('Z', utcOffsetString);
};
// E.g.
let date = new Date();
// Like 2020-08-04T14:52:38.613-07:00
console.log(`UTC : ${date.toISOString()}\n` +
`Local: ${date.toLocalISOString()}`);
// Stand alone function
function toISOLocal(date) {
let offsetMins = date.getTimezoneOffset();
let d = new Date(date - offsetMins*6e4);
let offsetSign = offsetMins > 0? '-' : '+';
offsetMins = Math.abs(offsetMins);
let offsetHr = String(offsetMins / 60 | 0).padStart(2,'0');
let offsetMin = String(offsetMins % 60).padStart(2,'0');
return d.toISOString().replace('Z', `${offsetSign}${offsetHr}:${offsetMin}`);
}
// Like 2020-08-04T14:52:38.613-07:00
console.log(`fn : ${toISOLocal(date)}`);
ISO 8601 is simply a way of formatting dates and can as such can be applied to any time zone.
Have you tried the timeZone option to the Date object's toLocaleString method?
This question has answers with examples.
This is the method I use. It takes care to add zeros if date/month/hour etc is single digit number (for example turns '6' to '06')
function formatLikeISO (d: Date): string {
let lengthChecker = (str) => {
if (str.length == 1) { return '0' + str; }
return str;
}
let theDate = lengthChecker(String(d.getDate()));
let month = lengthChecker(String(d.getMonth() + 1));
let mins = lengthChecker(String(d.getMinutes()));
let hours = lengthChecker(String(d.getHours()));
let secs = lengthChecker(String(d.getSeconds()));
let formatted =
d.getFullYear() + '-' +
month + '-' +
theDate + ' ' +
hours + ':' +
mins + ':' +
secs;
return formatted;
}
This will output this kind of format:
"2021-06-30 11:31:34"
There's no direct way to do this. However, you can use toLocaleString to create a string that you can easily parse to make it an ISO string.
This works on node:
function getLocalIsoTime(time, timezone) {
const local = time.toLocaleString("en-US", {timeZone: timezone, hour12: false, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
return `${local.substr(6, 4)}-${local.substr(0, 2)}-${local.substr(3, 2)}T${local.substr(12, 8)}`;
}
console.log(getLocalIsoTime(new Date(), 'Asia/Kolkata'));
A simpler version works on node 15+ and on most modern browsers:
function getLocalIsoTime(time, timezone) {
return time.toLocaleString("en-CA", {timeZone: timezone, hour12: false}).replace(/, /, "T");
}
console.log(getLocalIsoTime(new Date(), 'Asia/Kolkata'));
Based on https://stackoverflow.com/a/68191554/833960, but I wanted the ms to be present and consistent width output of 3 digits for ms.
function formatLikeISO(d: Date): string {
let lengthChecker = (str: string, targetLen = 2) => {
if (str.length < targetLen) {
return str.padStart(targetLen, '0')
}
return str
}
let day = lengthChecker(String(d.getDate()))
let month = lengthChecker(String(d.getMonth() + 1))
let mins = lengthChecker(String(d.getMinutes()))
let hours = lengthChecker(String(d.getHours()))
let secs = lengthChecker(String(d.getSeconds()))
let ms = lengthChecker(String(d.getMilliseconds()), 3)
let formatted =
d.getFullYear() +
'-' +
month +
'-' +
day +
' ' +
hours +
':' +
mins +
':' +
secs +
'.' +
ms
return formatted
}
Output:
2023-02-13 10:23:59.025
2023-02-13 10:23:59.026
2023-02-13 10:23:59.026
2023-02-13 10:23:59.030
2023-02-13 10:23:59.438
2023-02-13 10:23:59.438

javascript date.toString("yyyy-MM-ddTHH:mm:ss.fffZ") or "yyyy-MM-dd HH:mm:ss ZZ" with timezone offset [duplicate]

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. 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.
Get local time with format
var local = new Date().format("yyyy-MM-ddThh:mm:ss"); // 2013-07-02T09:00:00
Get UTC time offset by hour
var offset = local.getTimezoneOffset() / 60; // 7
Construct URL (time part only)
var duration = local + "-" + offset + ":00"; // 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 documentation.
Here's a simple helper function that will format JS dates for you.
function toIsoString(date) {
var tzo = -date.getTimezoneOffset(),
dif = tzo >= 0 ? '+' : '-',
pad = function(num) {
return (num < 10 ? '0' : '') + num;
};
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
dif + pad(Math.floor(Math.abs(tzo) / 60)) +
':' + pad(Math.abs(tzo) % 60);
}
var dt = new Date();
console.log(toIsoString(dt));
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.
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.
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;
}
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 ? '-' : '+') +
Math.floor(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'
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 cents 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
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
date to ISO string,
with local(computer) time zone,
with or without milliseconds
ISO ref: https://en.wikipedia.org/wiki/ISO_8601
how to use: toIsoLocalTime(new Date())
function toIsoLocalTime(value) {
if (value instanceof Date === false)
value = new Date();
const off = value.getTimezoneOffset() * -1;
const del = value.getMilliseconds() ? 'Z' : '.'; // have milliseconds ?
value = new Date(value.getTime() + off * 60000); // add or subtract time zone
return value
.toISOString()
.split(del)[0]
+ (off < 0 ? '-' : '+')
+ ('0' + Math.abs(Math.floor(off / 60))).substr(-2)
+ ':'
+ ('0' + Math.abs(off % 60)).substr(-2);
}
function test(value) {
const event = new Date(value);
console.info(value + ' -> ' + toIsoLocalTime(event) + ', test = ' + (event.getTime() === (new Date(toIsoLocalTime(event))).getTime() ));
}
test('2017-06-14T10:00:00+03:00'); // test with timezone
test('2017-06-14T10:00:00'); // test with local timezone
test('2017-06-14T10:00:00Z'); // test with UTC format
test('2099-12-31T23:59:59.999Z'); // date with milliseconds
test((new Date()).toString()); // now
consider using moment (like Matt's answer).
From version 2.20.0, you may call .toISOString(true) to prevent UTC conversion:
console.log(moment().toISOString(true));
// sample output: 2022-04-06T16:26:36.758+03:00
Use Temporal.
Temporal.Now.zonedDateTimeISO().toString()
// '2022-08-09T14:16:47.762797591-07:00[America/Los_Angeles]'
To omit the fractional seconds and IANA time zone:
Temporal.Now.zonedDateTimeISO().toString({
timeZoneName: "never",
fractionalSecondDigits: 0
})
// '2022-08-09T14:18:34-07:00'
Note: Temporal is currently (2022) available as a polyfill, but will soon be available in major browsers.
With luxon:
DateTime.now().toISODate() // 2022-05-23
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();
};
let myDate = new Date(dateToBeFormatted * 1000); // depends if you have milliseconds, or seconds, then the * 1000 might be not, or required.
timeOffset = myDate.getTimezoneOffset();
myDate = new Date(myDate.getTime() - (timeOffset * 60 * 1000));
console.log(myDate.toISOString().split('T')[0]);
Inspired by https://stackoverflow.com/a/29774197/11127383, including timezone offset comment.
a simple way to get:
//using a sample date
let iso_str = '2022-06-11T01:51:59.618Z';
let d = new Date(iso_str);
let tz = 'America/Santiago'
let options = {
timeZone:tz ,
timeZoneName:'longOffset',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
fractionalSecondDigits: 3
}
str_locale = d.toLocaleString("sv-SE",options);
iso_str_tz = str_locale.replace(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2}),(\d+)\s+/,'$1-$2-$3T$4:$5:$6.$7').replace('GMT−', '-' ).replace('GMT+','+')
console.log('iso_str : ',iso_str);
console.log('str_locale : ',str_locale);
console.log('iso_str_tz : ',iso_str_tz);
console.log('iso_str_tz --> date : ',new Date(iso_str_tz));
console.log('iso_str_tz --> iso_str: ',new Date(iso_str_tz).toISOString());
Using moment.js, you can use keepOffset parameter of toISOString:
toISOString(keepOffset?: boolean): string;
moment().toISOString(true)
Alternative approach with dayjs
import dayjs from "dayjs"
const formattedDateTime = dayjs(new Date()).format()
console.log(formattedDateTime) // Prints 2022-11-09T07:49:29+03:00
Here's another way a convert your date with an offset.
function toCustomDateString(date, offset) {
function pad(number) {
if (number < 10) {
return "0" + number;
}
return number;
}
var offsetHours = offset / 60;
var offsetMinutes = offset % 60;
var sign = (offset > 0) ? "+" : "-";
offsetHours = pad(Math.floor(Math.abs(offsetHours)));
offsetMinutes = pad(Math.abs(offsetMinutes));
return date.getFullYear() +
"-" + pad(date.getMonth() + 1) +
"-" + pad(date.getDate()) +
"T" + pad(date.getHours()) +
":" + pad(date.getMinutes()) +
":" + pad(date.getSeconds()) +
sign + offsetHours +
":" + offsetMinutes;
}
Then you can use it like this:
var date = new Date();
var offset = 330; // offset in minutes from UTC, for India it is 330 minutes ahead of UTC
var customDateString = toCustomDateString(date, offset);
console.log(customDateString);
// Output: "2023-02-09T10:29:31+05:30"
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;
}
I found another more easy solution:
let now = new Date();
// correct time zone offset for generating iso string
now.setMinutes(now.getMinutes() - now.getTimezoneOffset())
now = now.toISOString();
I undo the timezone offset by substracting it from the current date object.
The UTC time from the date object is now pointing to the local time.
That gives you the possibility to get the iso date for the local time.

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. 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.
Get local time with format
var local = new Date().format("yyyy-MM-ddThh:mm:ss"); // 2013-07-02T09:00:00
Get UTC time offset by hour
var offset = local.getTimezoneOffset() / 60; // 7
Construct URL (time part only)
var duration = local + "-" + offset + ":00"; // 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 documentation.
Here's a simple helper function that will format JS dates for you.
function toIsoString(date) {
var tzo = -date.getTimezoneOffset(),
dif = tzo >= 0 ? '+' : '-',
pad = function(num) {
return (num < 10 ? '0' : '') + num;
};
return date.getFullYear() +
'-' + pad(date.getMonth() + 1) +
'-' + pad(date.getDate()) +
'T' + pad(date.getHours()) +
':' + pad(date.getMinutes()) +
':' + pad(date.getSeconds()) +
dif + pad(Math.floor(Math.abs(tzo) / 60)) +
':' + pad(Math.abs(tzo) % 60);
}
var dt = new Date();
console.log(toIsoString(dt));
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.
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.
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;
}
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 ? '-' : '+') +
Math.floor(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'
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 cents 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
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
date to ISO string,
with local(computer) time zone,
with or without milliseconds
ISO ref: https://en.wikipedia.org/wiki/ISO_8601
how to use: toIsoLocalTime(new Date())
function toIsoLocalTime(value) {
if (value instanceof Date === false)
value = new Date();
const off = value.getTimezoneOffset() * -1;
const del = value.getMilliseconds() ? 'Z' : '.'; // have milliseconds ?
value = new Date(value.getTime() + off * 60000); // add or subtract time zone
return value
.toISOString()
.split(del)[0]
+ (off < 0 ? '-' : '+')
+ ('0' + Math.abs(Math.floor(off / 60))).substr(-2)
+ ':'
+ ('0' + Math.abs(off % 60)).substr(-2);
}
function test(value) {
const event = new Date(value);
console.info(value + ' -> ' + toIsoLocalTime(event) + ', test = ' + (event.getTime() === (new Date(toIsoLocalTime(event))).getTime() ));
}
test('2017-06-14T10:00:00+03:00'); // test with timezone
test('2017-06-14T10:00:00'); // test with local timezone
test('2017-06-14T10:00:00Z'); // test with UTC format
test('2099-12-31T23:59:59.999Z'); // date with milliseconds
test((new Date()).toString()); // now
consider using moment (like Matt's answer).
From version 2.20.0, you may call .toISOString(true) to prevent UTC conversion:
console.log(moment().toISOString(true));
// sample output: 2022-04-06T16:26:36.758+03:00
Use Temporal.
Temporal.Now.zonedDateTimeISO().toString()
// '2022-08-09T14:16:47.762797591-07:00[America/Los_Angeles]'
To omit the fractional seconds and IANA time zone:
Temporal.Now.zonedDateTimeISO().toString({
timeZoneName: "never",
fractionalSecondDigits: 0
})
// '2022-08-09T14:18:34-07:00'
Note: Temporal is currently (2022) available as a polyfill, but will soon be available in major browsers.
With luxon:
DateTime.now().toISODate() // 2022-05-23
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();
};
let myDate = new Date(dateToBeFormatted * 1000); // depends if you have milliseconds, or seconds, then the * 1000 might be not, or required.
timeOffset = myDate.getTimezoneOffset();
myDate = new Date(myDate.getTime() - (timeOffset * 60 * 1000));
console.log(myDate.toISOString().split('T')[0]);
Inspired by https://stackoverflow.com/a/29774197/11127383, including timezone offset comment.
a simple way to get:
//using a sample date
let iso_str = '2022-06-11T01:51:59.618Z';
let d = new Date(iso_str);
let tz = 'America/Santiago'
let options = {
timeZone:tz ,
timeZoneName:'longOffset',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
fractionalSecondDigits: 3
}
str_locale = d.toLocaleString("sv-SE",options);
iso_str_tz = str_locale.replace(/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2}),(\d+)\s+/,'$1-$2-$3T$4:$5:$6.$7').replace('GMT−', '-' ).replace('GMT+','+')
console.log('iso_str : ',iso_str);
console.log('str_locale : ',str_locale);
console.log('iso_str_tz : ',iso_str_tz);
console.log('iso_str_tz --> date : ',new Date(iso_str_tz));
console.log('iso_str_tz --> iso_str: ',new Date(iso_str_tz).toISOString());
Using moment.js, you can use keepOffset parameter of toISOString:
toISOString(keepOffset?: boolean): string;
moment().toISOString(true)
Alternative approach with dayjs
import dayjs from "dayjs"
const formattedDateTime = dayjs(new Date()).format()
console.log(formattedDateTime) // Prints 2022-11-09T07:49:29+03:00
Here's another way a convert your date with an offset.
function toCustomDateString(date, offset) {
function pad(number) {
if (number < 10) {
return "0" + number;
}
return number;
}
var offsetHours = offset / 60;
var offsetMinutes = offset % 60;
var sign = (offset > 0) ? "+" : "-";
offsetHours = pad(Math.floor(Math.abs(offsetHours)));
offsetMinutes = pad(Math.abs(offsetMinutes));
return date.getFullYear() +
"-" + pad(date.getMonth() + 1) +
"-" + pad(date.getDate()) +
"T" + pad(date.getHours()) +
":" + pad(date.getMinutes()) +
":" + pad(date.getSeconds()) +
sign + offsetHours +
":" + offsetMinutes;
}
Then you can use it like this:
var date = new Date();
var offset = 330; // offset in minutes from UTC, for India it is 330 minutes ahead of UTC
var customDateString = toCustomDateString(date, offset);
console.log(customDateString);
// Output: "2023-02-09T10:29:31+05:30"
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;
}
I found another more easy solution:
let now = new Date();
// correct time zone offset for generating iso string
now.setMinutes(now.getMinutes() - now.getTimezoneOffset())
now = now.toISOString();
I undo the timezone offset by substracting it from the current date object.
The UTC time from the date object is now pointing to the local time.
That gives you the possibility to get the iso date for the local time.

Categories

Resources