在构建 Web 应用程序时,我们通常会考虑两种类型的时区。最常见的是服务器时间,它作为日期和时间跟踪的参考,非常简单。
但是,在某些情况下,我们需要跟踪最终用户的日期和时间。在这些情况下,我们需要使用 JavaScript 从用户的浏览器中捕获时间。此外,这些用户可能来自不同的时区,处理起来可能很棘手。
Time Zones GMT, Offset, UTC
在深入了解细节之前,让我们了解一些有关时区的术语。
1. GMT——通用参考
世界被划分为时区,每个时区都有其偏移量。此偏移量是添加到世界时间以获得每个国家/地区时区的分钟数。 为此,我们需要一个参考,即格林威治标准时间 (GMT)。它从北极到南极,经过伦敦旧皇家天文台的格林威治区。 如果您在格林威治子午线以东,您的当地时间通常比格林威治标准时间早(例如,中国当地时间是格林威治标准时间 +8 小时)。相反,当地时间在格林威治子午线以西的格林威治标准时间之后(例如,纽约当地时间在冬天是格林威治标准时间 -5 小时,在夏天是格林威治标准时间 -4 小时)。
2. 偏移 - 与参考的差异
时区偏移GMT之前或之后的小时数或分钟数。 由于夏令时的原因,时区的偏移量可能会全年发生变化。此外,法律可以改变时区的偏移或夏令时时间表。例如,当我们说印第安纳州从中部时间切换到东部时间时,印第安纳州的时区从一个偏移量转移到另一个偏移量。 国家通常以自己的名字命名时区。例如,韩国的时区被称为 KST(韩国标准时间),它有一个特定的偏移值KST = UTC+09:00。
3. UTC——更好的 GMT 替代方案
许多人错误地认为 GMT 和 UTC 是同一个东西,经常互换使用。但是如果我告诉你它们不一样呢? UTC 于 1972 年创建,旨在解决地球自转减速问题。在这个基于国际原子时的时间系统中,铯原子频率用于设定时间标准。换句话说,UTC 是 GMT 的更好替代品。但是,对于日常开发而言,差异几乎不明显。
var d = new Date();var n = d.getTimezoneOffset(); // 以分钟为单位返回 UTC 偏移量
JavaScript 为 Date 对象提供了各种方法来执行与日期和时间相关的计算。但是,您可以选择使用它或使用更多增强的库在代码中执行日期时间处理。让我们首先看看我们从 JavaScript 日期对象中得到了什么。
日期时间操作——使用纯 JavaScript
JavaScript 中的 Date 对象在内部使用绝对数字(例如 Unix 时间)管理时间数据。构造函数和方法,如parse(),getHour(),setHour().
但是,重要的是要注意它受客户端本地时区(准确地说是运行浏览器的操作系统的时区)的影响。因此,从用户输入数据生成 Date 对象将代表客户端的本地时区。日期对象在内部以 UTC 时间跟踪时间,但它通常以运行它的计算机的本地时间接受和输出数据。
但是,在 JavaScript 中,在处理跨不同时区的日期时间计算时,本机可用的方法有限。
但是,日期对象可以对非本地时区执行一项操作。
ISOString —它可以解析包含任何时区的数字 UTC 偏移量的文本。输出 Date 对象不保留原始本地时间和偏移量。
var d = newDate();
d.toISOString();
//=> "2021-09-06T13:52:23.770Z"
d.valueOf();
//=> 1630936367439 (this is what is actually stored in the object)
日期时间操作——使用第三方库
有许多库提供了广泛的日期格式和操作功能。我们可以根据它们是否支持ECMAScript 国际化 API 将这些库分为两种类型。
基于国际标准的三方库
新的开发应该使用这些时区实现之一,它们使用 Intl API 来处理它们的数据:
Luxon (successor to Moment.js)
date-fns-tz (extension for date-fns )
非国际标准的三方库
这些库保持最新状态,但它们负责打包它们的时区数据,这些数据可能很大。
js-joda/timezone (extension for js-joda)
date-fns-timezone (extension for older 1.x of date-fns)
BigEasy/TimeZonetz.js
此外,必须避免为新项目使用一些已停止更新的库。
这些库已退役,不应再使用。
MomentJS
WallTime-js
TimeZoneJS
其中,我相信你们中的大多数人都熟悉 Moment,但是,Moment 团队现在建议使用 Luxon 进行未来的开发。
我的最爱——Date-fns
Date-fns 是一个小型库,具有简单的 API 和许多小功能。有近 140 个函数,Date-fn日期被称为 Lodash。
Date-fns 具有以下优点:
- Immutable and pureNative
- date
- Modular
- Fast
- Documentation
- I18n
- Typescript and Flow
- npm 包集合包括 Date-fns。您可以使用命令安装 date-fns。
npm install date-fns - Date-fns 兼容 CommonJS 和 ES 模块。
您需要导入开始解析和显示日期所需的函数;你不需要导入整个 API(只需要你需要的)。让我们只显示当前日期。
//Import the function initially
const {format} = require('date-fns');
//today's date
const today =format(newDate(),'dd.MM.yyyy');
console.log(today);
为了使用 UTC 或 ISO 日期字符串,Date-fns 支持时区数据。这将允许您以用户的本地时间显示日期和时间。当使用多个时区时,挑战就来了。让我们通过一个例子来看看我们如何处理这些情况。
引用 — 首先,时间戳、UTC 或 ISO 日期字符串表示固定的时间点。特定时区 - 其次,时区描述符(例如美国/洛杉矶)通常是偏移量或 IANA 时区名称。注意:您需要使用 npm install date-fns-tz.
- 分区时间为 UTC
const { format, zonedTimeToutc } = require('date-fns-tz');
const today = new Date();
const timezone = 'Europe/Paris'; // Let's see what time it is Down Under
const timeInBrisbane = zonedTimeToUtc(today, timeZone);
console.log(`
Default time zone:${format(today,'yyyy-MM-dd HH:mm:ss')}
Time in Paris:${format(timeInBrisbane, 'yyyy-MM-dd HH:mm:ss')}
`)
- UTC 到分区时间
const { format, utcToZonedTime } = require('date-fns-tz');
const today = new Date();
const timezone = 'Europe/Paris'; // Let's see what time it is Down Under
const timeInBrisbane = utcToZonedTime(today, timeZone);
console.log(`
Default time zone:${format(today,'yyyy-MM-dd HH:mm:ss')}
Time in Paris:${format(timeInBrisbane, 'yyyy-MM-dd HH:mm:ss')}
`)
结论
有几个库可用于处理时区。它们通常实现标准的 IANA 时区数据库并提供在 JavaScript 中使用它的函数,尽管它们不能使 Date 对象的行为有任何不同。
现代库使用 Intl API 的时区数据,而较旧的库通常有开销,尤其是在 Web 浏览器中运行时,因为数据库可能会变得相当大。
但是,如果您为新项目选择一个库,请选择一个支持 Intl API 的库,这可能是面向未来的。否则,如果您只处理几个 Date 时间操作,使用原生 Date 对象也可以。