Reputation: 9859
I do not want to use any external libs like momentjs, I want to create a formatted date string myself. I tried to use new Date().toISOString()
but it's losing time-zone.
This:
new Date()
Gives:
Sat Jun 24 2017 09:32:10 GMT+0300 (RTZ 2 (winter))
And:
new Date().toISOString();
Gives:
2017-06-24T06:32:22.990Z
And 09:32:10
is the right time, so 06:32:22
hass lost timezone information.
To add to this, it looks like new Date().toLocaleString()
does almost what I need. At last hours is correct. Result: "24.06.2017, 11:37:05"
.
Upvotes: 8
Views: 11669
Reputation: 17854
In the updated Question you propose using toLocaleString(), and yes this will get the date into the users' current locale (vs. toISOString which always uses GMT), but you've lost the ISO 8601 formatting.
The solution that I use is to set the locale to a country that uses 8601, eg.
const d = new Date();
const dateStr = d.toLocaleString( 'sv' );
// locale 'sv' is Sweden so you get ISO 8601 format
The result will have a space instead of the 'T' but that is legal in RFC 3339.
[edit: clarified that is is RFC 3339 that allows the space, as per T.J. Crowder comment.]
Upvotes: 4
Reputation: 1074168
JavaScript Date
objects don't store timezone information. They use the system timezone, and that's it. So once you have a Date
, you've lost timezone information (other than the current system's timezone).
From a Date
, you can get the current timezone offset, and you can form a string in ISO-8601 format using that timezone offset:
function pad(x, width = 2, char = "0") {
return String(x).padStart(width, char);
}
function toLocalISOString(dt) {
const offset = dt.getTimezoneOffset();
const absOffset = Math.abs(offset);
const offHours = Math.floor(absOffset / 60);
const offStr = pad(offHours) + ":" + pad(absOffset - offHours * 60);
return [
String(dt.getFullYear()),
"-",
pad(dt.getMonth() + 1),
"-",
pad(dt.getDate()),
"T",
pad(dt.getHours()),
":",
pad(dt.getMinutes()),
":",
pad(dt.getSeconds()),
".",
dt.getMilliseconds(),
offset <= 0 ? "+" : "-",
offStr
].join("");
}
console.log(toLocalISOString(new Date()));
...but an offset isn't a timezone; an offset only tells you how many hours and minutes offset from UTC a date/time is, not what rules govern it.
In any modern browser (not IE11), you can get the actual timezone from Intl.DateTimeFormat().resolvedOptions().timeZone
, which will give you an IANA string like "Europe/London"
. You could include that in your custom string, perhaps conditionally based on being able to get it:
function pad(x, width = 2, char = "0") {
return String(x).padStart(width, char);
}
function toLocalISOString(dt) {
const offset = dt.getTimezoneOffset();
const absOffset = Math.abs(offset);
const offHours = Math.floor(absOffset / 60);
const offStr = pad(offHours) + ":" + pad(absOffset - offHours * 60);
let parts = [
String(dt.getFullYear()),
"-",
pad(dt.getMonth() + 1),
"-",
pad(dt.getDate()),
"T",
pad(dt.getHours()),
":",
pad(dt.getMinutes()),
":",
pad(dt.getSeconds()),
".",
dt.getMilliseconds(),
offset <= 0 ? "+" : "-",
offStr
];
if (typeof Intl === "object" && Intl.DateTimeFormat) {
try {
parts.push(
" (",
Intl.DateTimeFormat().resolvedOptions().timeZone,
")"
);
} catch (e) {
}
}
return parts.join("");
}
console.log(toLocalISOString(new Date()));
Upvotes: 1
Reputation: 1206
Answer from a similar question
moment.js is great but sometimes you don't want to pull a lage number of dependencies for a 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); // => '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.
Upvotes: 3