I am trying to convert a UTC timestamp to an ISO-formatted timestamp in German time.
Input: 2022-04-30T17:30:00.000000Z
Expected Output: 2022-04-30T19:30:00
This is my current, working solution but it feels very... hacky... to say the least. For one, I am afraid that many browsers might not be able to correctly convert the date to the german timezone.
var inputDateString = "2022-04-30T17:30:00.000000Z";
// Convert to German timezone and formatted as iso date
var output = toIsoString(convertTZ(inputDateString, "Europe/Berlin")).split(" ")[0];
console.log("inputDateString:", inputDateString)
console.log("output:", output)
// Ref.: https://stackoverflow.com/a/54127122
function convertTZ(date, tzString) {
return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", { timeZone: tzString }));
}
// Ref.: https://stackoverflow.com/a/17415677
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);
}
Do you know a better/improved solution to this problem that is compatible with most browsers? I feel like JavaScript must offer a better solution for this task without having to rely on external libraries...
Edit:
As an alternative to the toIsoString
function, I have also found this: .toLocaleString("sv-SE")
but I assume that this has even worse browser support.
CodePudding user response:
If you don't need to guarantee the format of the resulting timestamp, you can use toLocaleDateString plus toLocaleTimeString with a suitable language tag, e.g.
function getISOLocal(loc, date = new Date()) {
return `${date.toLocaleDateString('en-CA', {timeZone: loc})}`
`T${date.toLocaleTimeString('en', {timeZone: loc, hour12:false})}`;
}
console.log('Current local time in:');
['Pacific/Midway',
'America/New_York',
'Europe/Berlin',
'Pacific/Kiritimati'].forEach(
loc => console.log(`${loc} : ${getISOLocal(loc)}`)
);
But be aware that the format of toLocale* methods is implementation dependent and may vary between implementations, particularly for less common languages and combinations of language, options and host default language.
A better alternative is to use Intl.DateTimeFormat with formatToParts, e.g.
function getISOLocal(loc, date = new Date()) {
let {year, month, day, hour, minute, second} =
new Intl.DateTimeFormat('en', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
timeZone: loc
}).formatToParts(date).reduce((acc, part) => {
acc[part.type] = part.value;
return acc;
}, Object.create(null));
return `${year}-${month}-${day}T${hour}:${minute}:${second}`
}
console.log('Current local time in:');
['Pacific/Midway',
'America/New_York',
'Europe/Berlin',
'Pacific/Kiritimati'].forEach(
loc => console.log(`${loc} : ${getISOLocal(loc)}`)
);
The timeZone option isn't supported in IE, but maybe that doesn't matter.