将 UTC 时间戳转换为 ISO 格式的其他时区

Convert UTC timestamp to other timezone in ISO format

我正在尝试将 UTC 时间戳转换为德国时间的 ISO 格式时间戳。

输入:2022-04-30T17:30:00.000000Z

预期输出:2022-04-30T19:30:00

这是我目前的工作解决方案,但感觉非常...hacky...至少可以说。 其一,恐怕许多浏览器可能无法将日期正确转换为德国时区。

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.: 
function convertTZ(date, tzString) {
  return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", { timeZone: tzString }));
}

// Ref.: 
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);
}

您是否知道与大多数浏览器兼容的此问题的 better/improved 解决方案?我觉得 JavaScript 必须为这项任务提供更好的解决方案,而不必依赖外部库...

编辑: 作为 toIsoString 函数的替代方法,我还发现了这个:.toLocaleString("sv-SE") 但我认为这对浏览器的支持更差。

如果你不需要保证结果时间戳的格式,你可以使用 toLocaleDateStringtoLocaleTimeString 用合适的语言标签,例如

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

但请注意,toLocale* 方法的格式取决于实现,并且可能因实现而异,特别是对于不太常见的语言以及语言、选项和主机默认语言的组合。

更好的选择是使用 Intl.DateTimeFormatformatToParts,例如

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

IE 不支持 timeZone 选项,但也许这无关紧要。