Home > Software engineering >  Convert UTC timestamp to other timezone in ISO format
Convert UTC timestamp to other timezone in ISO format

Time:04-30

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.

  • Related