【问题标题】:JavaScript: how to get date time at a specified timezoneJavaScript:如何在指定时区获取日期时间
【发布时间】:2021-12-06 23:08:30
【问题描述】:

有没有办法在 JavaScript 中获取指定时区的本地时间?基本上,我在想办法说,纽约下午 2 点的 ISO 时间字符串是多少?

我有一个技巧,其中date 是可解析的日期字符串,tz 是时区标识符,例如America/New_York

function getDateInTZ(date, tz) {
  const formatter = new Intl.DateTimeFormat([], {
    year: "numeric",
    month: "numeric",
    day: "numeric",
    hour: "numeric",
    minute: "numeric",
    second: "numeric",
    fractionalSecondDigits: 3,
    timeZone: tz,
  });
  const localDate = new Date(date);
  const localDateAtTZ = new Date(formatter.format(localDate));
  const tzOffset = localDate.getTime() - localDateAtTZ.getTime();
  return new Date(localDate.getTime() + tzOffset);
}

它具有以下行为

getDateInTz("2021-07-01 20:05", "America/Chicago").toISOString(); // 2021-07-02T01:05:00.000Z
getDateInTz(new Date("2021-12-05 20:05"), "America/Chicago").toISOString(); // 2021-12-06T02:05:00.000Z

getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T02:05:00.000Z if local time is NY
getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T07:05:00.000Z if local time is UTC

虽然上述解决方案适用于 Chrome,但它不适用于 Firefox,因为 FF 无法对 formatter.format() 的输出执行 Date.parse。这让我认为这不是一个正确的解决方案。

之前有没有人遇到过这个需求,并且有好的解决方案?

【问题讨论】:

标签: javascript date firefox timezone


【解决方案1】:

据我所知,如果没有像 luxonday.js 这样的库的帮助,这是不可能的

在 luxon 中,这将是要走的路

let local = luxon.DateTime.local();  // 2021-10-31T20:26:15.093+01:00
let localInCT = local.setZone("America/Chicago"); //2021-10-31T14:26:15.093-05:00

使用这些方法查看this project

【讨论】:

    【解决方案2】:

    我们在这里受到 JavaScript 原生 Date 对象的限制。

    Date 对象的内部状态是自 1970 年 1 月 1 日 00:00 UTC 以来经过的毫秒数,并且没有时区存储在 Date 对象中。

    因此,我们可以创建与在另一个时区创建的日期有点等价的日期,但它们的行为不会完全相同:

    • Date.toString() 的时区偏移量将显示本地客户端时区(例如 GMT+0000),而不是所需时区的偏移量。

    • DST 规则可能无法按预期工作。我们可以得到相同的日期,比如 America/New_York,但 DST 转换将遵守当地时区规则,而不是纽约规则。

    话虽如此,您使用的方法的变体将在所需时区给出我称之为等效的日期。

    我们如何做到这一点:

    1. 首先使用Date.toLocaleString() 在所需时区中格式化 ISO 时间戳。我们使用 hack 来做到这一点,将“sv”语言环境传递给函数。这将创建一个 ISO 时间戳,例如yyyy-MM-dd HH:mm:ss.

    2. 将此时间戳传递给 Date() 构造函数。

    TLDR:真的做不到。但是对于某些上下文和用例,我们可以近似 期望的行为。为此,我建议使用像 luxon 这样的库。

    下面的例子:

    function getDateInTimezone(date, timeZone) {
        // Using a locale of 'sv' formats as an ISO date, e.g. yyyy-MM-dd HH:mm.
        const timeInTimeZone = date.toLocaleString('sv', { timeZone } );
        // Pass this to the Date constructor
        return new Date(timeInTimeZone);
    }
    
    const localTime = new Date();
    const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];
    
    console.log(`Local Time: ${localTime.toLocaleTimeString()}`);
    for(let timeZone of timeZoneList) {
        const dt = getDateInTimezone(localTime, timeZone);
        console.log(`Time (${timeZone}): ${dt.toLocaleTimeString()}`);
    }
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    luxon 中的时区更容易处理,而且当我们在 Luxon DateTime 上调用 .toString() 时,我们会得到正确的 UTC 偏移量。

    const { DateTime } = luxon;
    const localTime = DateTime.now();
    const timeZoneList = ['Asia/Tokyo', 'Europe/Berlin','America/Los_Angeles'];
    
    console.log(`Local Time: ${localTime.toFormat('HH:mm:ssZZ')}`);
    for(let zone of timeZoneList) {
        const dt = DateTime.fromMillis(Date.now(), { zone });
        console.log(`Time (${zone}): ${dt.toFormat(' HH:mm:ssZZ')}`);
    }
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.0.2/luxon.min.js" integrity="sha512-frUCURIeB0OKMPgmDEwT3rC4NH2a4gn06N3Iw6T1z0WfrQZd7gNfJFbHrNsZP38PVXOp6nUiFtBqVvmCj+ARhw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

    【讨论】:

      【解决方案3】:

      你可以这样使用:

      const actualDate = new Date()
      actualDate.toLocaleString('en-US', { timeZone: 'America/New_York' })
      

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      • 这不是我要问的。您正在做的是在不同的时区显示日期对象(在您的示例中为当前时间)。我要的是在那个时区得到一个特定的时间。
      【解决方案4】:

      这能解决你的问题吗?

      function getDateInTZ(date, tz) {
        return new Date(date).toLocaleString('en-US', { timeZone: tz })
      }
      
      console.log(getDateInTZ("2021-07-01 20:05", "Asia/Kolkata"))
      console.log(getDateInTZ("2021-07-01 20:05", "America/Chicago"))
      console.log(getDateInTZ("2021-12-06T02:05:00.000Z", "America/New_York"))

      【讨论】:

      • 感谢您的建议,但这并不能回答我的问题。首先,我需要该函数返回一个 Date 对象,而不是一个字符串。其次,它实际上并没有满足我的需要。 ``` // 预期 getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 2021-12-06T02:05:00.000Z 如果本地时间是 NY //实际 getDateInTZ("2021-12-06T02:05:00.000Z", "America/New_York") '12/5/2021, 9:下午 05:00' ```
      【解决方案5】:
      let date = new Date();
      let time = date.toLocaleTimeString([], { hour12: true }) 
      

      如果我们使用hour12 true,它将以12h格式返回时间,否则它将以24h格式返回时间 确保我们在 .env 文件上使用 TZ,这一直是一种很好的做法,有助于清除所有额外的代码。

      你可以简单地使用

      TZ=America/New_York
      

      【讨论】:

        猜你喜欢
        • 2018-11-25
        • 1970-01-01
        • 2018-12-30
        • 2014-01-17
        • 2021-09-24
        • 2014-04-21
        • 1970-01-01
        • 2016-03-12
        • 2017-05-02
        相关资源
        最近更新 更多