发布于 2026-01-06 1 阅读
0

如何在 Javascript 中移除日期中的时区

如何在 Javascript 中移除日期中的时区

前言

我已经很久没在这里写东西了。我计划在这里写一些篇幅较短的文章,内容是关于我日常工作中解决的问题。

背景

前几天我在为我的旅行规划创业公司Tripley开发 React Native 应用时,遇到了一个比较特殊的问题。在创建旅行日历中的事件时,它会根据当前时区存储日期。

关于时区有点(太多)

时区地图

为了防止世界一端的人们在黑暗中吃午饭,人们设立了时区。太平洋标准时间 (PST) 比东部标准时间 (EST) 晚 3 小时。这意味着旧金山的时间与纽约的时间1:00相同。4:00

每个时区都对应一个与英国伦敦时区相关的代码。伦敦的时区是格林威治标准时间 (GMT)。为什么是伦敦?因为帝国主义。

世界协调时间 (UTC) 源自格林尼治标准时间 (GMT)(两者时间基本相同)。UTC 与伦敦时间的主要区别在于 UTC 不受夏令时的影响。当英国实行夏令时并切换到英国夏令时 (BST) 时区时,UTC 时间保持不变。

每个时区都会获得一个相对于英国伦敦时区的代码。

回到正题。每个时区都有一个相对于UTC时间的小时数。太平洋标准时间(PST)的“代码”是UTC-8,表示PST比UTC时间晚8小时。这不仅仅局限于小时数。例如,尼泊尔的时区代码是UTC+05:45,表示它比UTC时间早5小时45分钟。英国夏令时(BST)甚至还有一个UTC代码,即UTC+1。在英国实行夏令时期间,BST时区比UTC时间早1小时。

问题

这对我们来说是个大问题。假设您August 8th, 2023 at 4:30 PM身处旧金山并进行了选择。根据 JavaScript 的特性,日期会被记录为 UTC 时间(在本例中为 1999 年 12 月 1 日August 8th, 2023 at 11:30 PM UTC)。如果您前往夏威夷瓦胡岛,那么您将处于 HST 时区(夏威夷标准时间),比 PST(太平洋标准时间)晚 3 小时。

您原定于下午 4:30 发生的事件现在会显示为下午 1:30。这是因为 JavaScript 会根据您当前的时区自动调整 UTC 日期,将其转换为 HST 时区。

假设我们有一个名为 `date` 的 JS 日期变量date,我们在旧金山运行了以下代码:



//Wed Feb 22 2023 14:00:43 GMT-0800 (Pacific Standard Time)
console.log(date);


Enter fullscreen mode Exit fullscreen mode

如果这项活动在檀香山举行,情况就会有所不同:



//Wed Feb 22 2023 11:00:43 GMT-1000 (Hawaiian Aleutian Time)
console.log(date);


Enter fullscreen mode Exit fullscreen mode

无论在哪个时区,如果使用该方法打印日期.toISOString(),都会得到 ISO 8061 格式的日期:



//2023-02-22T22:00:43.000Z
console.log(date.toISOString())


Enter fullscreen mode Exit fullscreen mode

这个 ISO 字符串是 UTC 时间。如果我们分析这个字符串,可以看到T字符串中有一个分隔符。因此,字符串分为两部分:2023-02-22日期和时间22:00:43.000Z。第一部分很容易识别,它是日期!第二部分是时间字符串。

我们最初的 PST 日期是 [日期] 14:00:43,但这个日期显示为[日期22:00:43]?这是因为日期是以 UTC 时间存储的。PST 时区比 UTC 晚 8 小时,对吧?如果加上8 hours[日期] 14:00:43,你会得到[日期22:00:43]!

解决方案

得知此事后,我尝试了几种方法。首先,我尝试看看是否可以省略时区。我的第一反应是使用这种.toLocaleString()方法。

它看起来会是这样的:



const date = new Date();

// "2/23/2023, 1:48:30 PM"
console.log(date.toLocaleString())


Enter fullscreen mode Exit fullscreen mode

我决定将这个字符串(2/23/2023, 1:48:30 PM)存入数据库。我想之后可以Date像这样,将它作为参数传递给客户端的构造函数:



new Date("2/23/2023, 1:48:30 PM")


Enter fullscreen mode Exit fullscreen mode

我在MDN Web Docs JS Date Playground中测试了上述代码,我的电脑时区分别设置为 PST 和 HST:


代码在太平洋标准时间 (PST) 下运行


代码在 HST 时区运行

我查看了两个结果,它们完全一样!我最终想到了一个绝妙的解决方案:存储输出结果,然后在客户端再次.toLocaleString()将其转换为,整个过程都不​​考虑时区。Date

然而,当我在我的 React Native 应用中实现这个解决方案时,它却不起作用。它一直提示我传递给Date构造函数的日期无效。我在网上搜索了一下,然后在 MDN Web 文档中找到了以下内容:

文档上的对话框提示:注意:由于浏览器差异和不一致,强烈建议不要使用 Date.parse 解析字符串。

这让我明白了为什么代码在浏览器中可以运行,但在我的 React Native 应用中却不行。原来 Firefox 中的 JS 运行在与 React Native 不同的运行时环境中。

关于JS引擎的简要说明

由于 JavaScript 的组织结构较为松散,JS 代码通常运行在称为引擎的特定环境中。每个浏览器都有自己的引擎:Chrome 使用 V8 引擎,Firefox 使用 SpiderMonkey 引擎,Safari 使用 JavaScriptCore。

以 React Native 为例,它使用了一个名为Hermes的引擎:
爱马仕标志

我分别在 Firefox(使用 SpiderMonkey 引擎)和 React Native 应用(使用 Hermes 引擎)中测试代码。这两个引擎在Date构造函数解析给定字符串的方式上肯定存在差异。

第二轮解决方案

两个小时后,我意识到第一个想法行不通,于是又想出了另一个办法。

如果我们Date使用给定的 ISO 字符串创建一个对象,UTC 时间将自动转换为当前时区。



const date = new Date('2023-02-22T22:00:43.000Z')

// Wed Feb 22 2023 14:00:43 GMT-0800 (Pacific Standard Time)
console.log(date)


Enter fullscreen mode Exit fullscreen mode

现在,如果我们从 ISO8601 字符串的末尾删除“” Z,则时区不会自动转换。



// notice the change
const date = new Date('2023-02-22T22:00:43.000')

// Wed Feb 22 2023 22:00:43 GMT-0800 (Pacific Standard Time)
console.log(date)


Enter fullscreen mode Exit fullscreen mode

输出console.log2:00 PM10:00 PM

伪代码?

我的想法是这样的。为了简单起见,我们从应用程序的日期选择器中选择日期和时间:Feb 22 2023 at 4:30 PM

如果我们获取console.logDate对象的 ISO8061 字符串,我们将得到:



2023-02-23T00:30:00.000Z


Enter fullscreen mode Exit fullscreen mode

请注意,日期比我们设定的时间早一天,时间也早 8 小时。我们可以简单地从 UTC 时间中减去 8 小时(因为我是在太平洋标准时间 (PST) 下创建的),来抵消这个差异。

如果我们这样做(减去 8 小时),我们得到



2023-02-22T16:30:00.000Z


Enter fullscreen mode Exit fullscreen mode

但是,如果我们创建一个新Date对象console.log,就会得到以下字符串:



Wed Feb 22 2023 22:00:43 GMT-0800 (Pacific Standard Time)


Enter fullscreen mode Exit fullscreen mode

我们仍然可以看到 UTC 时间被转换成了本地时间。我们可以通过删除ZISO8601 字符串末尾的那个字符来解决这个问题。

生成的 ISO8601 字符串如下所示:



2023-02-22T16:30:00.000


Enter fullscreen mode Exit fullscreen mode

现在,如果我们把console.log给定的Date对象放在旧金山,我们会得到以下字符串:



Wed Feb 22 2023 16:30:00 GMT-0800 (Pacific Standard Time)


Enter fullscreen mode Exit fullscreen mode

现在,尽管时区信息仍然存在console.log,但如果我们在檀香山运行相同的代码,我们会得到



Wed Feb 22 2023 16:30:00 GMT-1000 (Hawaiian Aleutian Time)


Enter fullscreen mode Exit fullscreen mode

这两个日期完全吻合!以下是伪代码的实际实现:



export const dateWithoutTimezone = (date: Date) => {
  const tzoffset = date.getTimezoneOffset() * 60000; //offset in milliseconds
  const withoutTimezone = new Date(date.valueOf() - tzoffset)
    .toISOString()
    .slice(0, -1);
  return withoutTimezone;
};


Enter fullscreen mode Exit fullscreen mode

首先tzoffset初始化一个新的 Date 对象,并获取时区偏移量(以毫秒为单位)(在我的例子中,偏移量为 28800000 毫秒)。

然后,我们从 的值中减去该值date,即10:30 PM,所以现在的值是4:30 PM。然后,我们从 ISO 字符串中截取末尾部分Z,这样 JS 就不会将其视为 UTC 时间并进行转换。

好了!该函数返回一个 ISO 字符串,现在我们可以将其存储在数据库中。

要再次解析此日期,您只需运行:



new Date("2023-02-22T16:30:00.000")


Enter fullscreen mode Exit fullscreen mode

如果我们console.log那样做,我们就能得到



Wed Feb 22 2023 16:30:00 GMT-1000 (Hawaiian Aleutian Time)


Enter fullscreen mode Exit fullscreen mode

结尾

嘿,谢谢你阅读我的博客!我打算写一些短篇博客(如果学业不耽误的话)。

我好久没写博客了,不过这段时间我创立了Tripley ,一款能帮你更轻松地规划和出行的应用程序。如果你能加入我们的候补名单,并在TwitterInstagram上关注我们,那对我们帮助就太大了。谢谢!

如果你想了解更多我的日常想法,请关注我的推特,非常感谢!

文章来源:https://dev.to/shubhampatilsd/removing-timezones-from-dates-in-javascript-46ah