JavaScript:如何获取指定时区的日期时间

4

在JavaScript中是否有一种方法可以获得与指定时区本地相关的时间?基本上,我想知道,在纽约时间下午2点的ISO时间字符串是什么。

我有一个hack来做到这一点,其中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中无法对formatter.format()的输出执行Date.parse,这导致我认为它不是一个正确的解决方案。

是否有人之前遇到过这种情况,并且有一个好的解决方案呢?


也许你真的想要一个纯JS的解决方案?不过,我强烈推荐https://www.npmjs.com/package/moment-timezone。 - FishSaidNo
@FishSaidNo,你有使用moment-timezone的代码可以实现我所说的功能吗? - Tri Nguyen
请查看以下链接:https://stackoverflow.com/questions/66630818/convert-date-to-another-timezone-in-javascript-and-print-with-correct-timezone - Corrl
5个回答

1
据我所知,如果没有像 luxon 或者 day.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

请看使用这些方法的这个项目


1
我们在这里受到 JavaScript 本地 Date 对象的限制。
Date 对象的内部状态是自1970年01月01日00:00 UTC以来经过的毫秒数,并且没有时区存储在 Date 对象中。
因此,我们可以创建与在另一个时区创建的日期相当的日期,但它们不会完全相同:
  • Date.toString() 的时区偏移将显示本地客户端时区(例如 GMT+0000),而不是所需时区的偏移。

  • 夏令时规则可能无法按预期工作。我们可以获得等效于美国/纽约的日期,但 DST 转换将遵循本地时区规则而不是纽约规则。

话虽如此,你正在使用的方法的变体将在所需时区中给出我所谓的“等效”日期。
我们如何做到这一点:
首先使用Date.toLocaleString()将ISO时间戳格式化为所需时区。我们使用一个技巧来实现这一点,将'sv'本地设置传递给该函数。这将创建一个ISO时间戳,例如yyyy-MM-dd HH:mm:ss。
然后将此时间戳传递给Date()构造函数。
简而言之:这不能真正实现。但对于某些上下文和用例,我们可以近似实现所需的行为。我建议使用像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>


0
你可以使用类似这样的代码:
const actualDate = new Date()
actualDate.toLocaleString('en-US', { timeZone: 'America/New_York' })

你的回答可以通过添加更多支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何撰写良好答案的更多信息。 - Maik Hasler
这不是我要问的。你所做的是在不同的时区显示日期对象(在你的例子中是当前时间)。我要求的是获取该时区的特定时间。 - Tri Nguyen

0

这个解决了你的问题吗?

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"))


谢谢您的建议,但这并没有回答我的问题。首先,我需要该函数返回一个日期对象,而不是一个字符串。其次,它实际上并不能完成我需要的任务。// 期望得到结果 getDateInTz("2021-12-06T02:05:00.000Z", "America/New_York").toISOString(); // 如果本地时间是纽约时间,则为 2021-12-06T02:05:00.000Z // 实际结果 getDateInTZ("2021-12-06T02:05:00.000Z", "America/New_York") '12/5/2021, 9:05:00 PM' - Tri Nguyen

-1
let date = new Date();
let time = date.toLocaleTimeString([], { hour12: true }) 

如果我们使用 hour12 为 true,它将返回 12 小时制的时间,否则将返回 24 小时制的时间。确保我们在 .env 文件中使用TZ,这始终是一个好习惯,并有助于消除所有额外的代码。

你可以简单地使用:

TZ=America/New_York

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接