【问题标题】:Create a date object in a specific time zone and convert it to UTC in JavaScript在特定时区创建日期对象并在 JavaScript 中将其转换为 UTC
【发布时间】:2022-07-13 21:58:19
【问题描述】:

我的应用程序当前正在以以下格式存储特定事件的日期和时间:

date: 2022-05-06
time: 00:00 // (12:00 AM)

每个事件的时间还包含一个与之关联的 TimeZone。如果组织活动的人来自新加坡,那么时区将是Asia/Singapore

当我向参加者发送此活动的日历邀请时,我想以 UTC 时间发送,以便在收件人结束时,它会在他们的时区中。 (注意:我使用ics 包来创建日历事件)。

所以,我想要的是在新加坡时区(根据上面的示例)创建一个带有 time = 2022-05-06 00:00 的日期对象,然后将其转换为 UTC,这应该是 2022-05-05 16:00(因为亚洲/新加坡是 UTC+8 )。我怎样才能做到这一点?

提前致谢。

【问题讨论】:

  • 已对类似主题进行了一些考虑herethis 也可能相关,尤其是链接问题。
  • 为什么不将事件存储为默认为 UTC 的 unix 时间戳?会更容易转换。
  • 我强烈推荐你在javascript中使用momentjs来处理日期
  • @Tony ... 关于迄今为止提供的所有答案/方法/解决方案,还有什么问题吗?

标签: javascript date timezone locale datetime-format


【解决方案1】:

一种可能的方法必须建立在一些先决条件之上

  • 传递的日期时间字符串需要是一个可解析的字符串,代表目标时区的本地日期,因此它不包含可解析的时区偏移数据。
  • 时区以name which is conform 的形式提供给IANATime Zone Database

那么实现如下

  • 从可解析的日期代表(数字或字符串值)创建Date 实例。

    • 注意 ...此日期对象已经带有其自己的时区偏移量,该偏移量由运行脚本的客户端/环境确定。
  • 为了生成以后易于解析的符合 UTC 的自定义字符串格式,该方法使用了 Intl.DateTimeFormatIntl.DateTimeFormatformat 方法。

    • 注意 ... options 参数的配置设置为返回自定义 UTC 日期时间字符串格式的唯一目标,在该格式中可以轻松解析日期时区偏移量(而不是时区名称提供,但以 '+hh:mm''-hh:mm' 形式的数字值)
  • 时区偏移的小时和分钟通过正则表达式检索... /([+-]\d{2}):(\d{2})$/ 匹配字符串末尾的模式和captures offsetHoursoffsetMinutes 子字符串。

  • 两个字符串值都被解析为基于分钟的总数值。

  • 现在提供的时区名称相对于日期对象的本地/客户端时间具有基于分钟的偏移量,需要由the date's own timezone offset 补偿

  • 最后一步是创建一个新日期,该日期具有与提供的时区名称与 UTC 相关的更正时区偏移量,这是通过日期的 getTime 值和前一分钟的总毫秒数以毫秒为基础完成的。

    • 现在可以选择将日期返回为toUTCString 或通过Intl.DateTimeFormat.format 再次作为自定义UTC 符合字符串返回,其中可以选择例如'lt'(立陶宛语)作为 locales 字符串参数,因为立陶宛语支持 'YYYY-MM-DD' 的日期格式(带有连接破折号)。

function createCustomUTCDateStringFromLocalDateAndTimeZoneName(
  parsableDateWithoutTimeZoneOffset,
  ianaTimeZoneName,
) {
  const formatConfig = {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour12: false,
    hour: '2-digit',
    minute: '2-digit',
    timeZone: 'UTC',
  };
  const date = new Date(parsableDateWithoutTimeZoneOffset);
  const format = new Intl.DateTimeFormat('en', {
    ...formatConfig,
    weekday: 'short',
    month: 'long',
    second: '2-digit',
    timeZone: ianaTimeZoneName,
    timeZoneName: 'longOffset',
  }).format(date);

  let [_, offsetHours = 0, offsetMinutes = 0] = format
    .match(/([+-]\d{2}):(\d{2})$/) ?? [];

  offsetMinutes = (parseInt(offsetHours, 10) * 60)
    + parseInt(offsetMinutes, 10)
    + date.getTimezoneOffset();

  // return new Date(
  //   date.getTime() - (offsetMinutes * 60000)
  // )
  // .toUTCString();

  return new Intl.DateTimeFormat('lt', formatConfig)
    .format(date.getTime() - (offsetMinutes * 60000));
}

[
 ['2022-05-06T00:00', 'Asia/Singapore'],
 ['2022-05-06T00:00', 'Asia/Kabul'],
 ['2022-05-06T00:00', 'Asia/Istanbul'],
 ['2022-05-06T00:00', 'Europe/Amsterdam'],
 ['2022-05-06T00:00', 'UTC'],
 ['2022-05-06T00:00', 'America/Jamaica'],
 ['2022-05-06T00:00', 'America/Anchorage'],
 ['2022-05-06T00:00', 'Pacific/Marquesas'],
 ['2022-05-06T00:00', 'Pacific/Honolulu'],
 ['2022-05-06T00:00', 'Pacific/Chatham']
].forEach(([date, loc]) =>
  console.log(`createCustomUTCDateStringFromLocalDateAndTimeZoneName(${date}, ${loc}) ...`,
  createCustomUTCDateStringFromLocalDateAndTimeZoneName(date, loc))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

【讨论】:

    【解决方案2】:

    const date = new Date('2020-04-13T00:00:00.000Z').toLocaleString('en-SG').split('T')
    console.log(date)

    【讨论】:

      猜你喜欢
      • 2021-08-16
      • 2011-08-30
      • 2015-12-10
      • 2017-11-07
      • 1970-01-01
      • 2021-11-19
      • 2021-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多