JavaScript划分日期库 - 完全DST支持
#javascript #本地化 #internationalization #timezone

npm软件包链接:https://www.npmjs.com/package/zoned-date

术语

关于日期时间:

  • 壁挂式:您的墙壁,日历中显示的值,即:年,月,日期,日(工作日),小时,分钟,第二,毫秒,时区偏移。
  • 时代:时间轴流中的一个点,由历史上特定时间的秒数识别。

理由

在JavaScript中,所有Wallclock方法均基于运行时的配置返回不同的结果。 date.getHours()在客户端浏览器,服务器和您的本地开发机中运行时返回不同的结果(对于具有相同date.getTime()值的日期对象)。

完美解决与约会有关的问题

我最近在JavaScript中发布zoned-date所有与日期有关的问题。

安装

yarn add zoned-date
import {ZonedDate, OffsetDate} from 'zoned-date'
// or
import ZonedDate from 'zoned-date/ZonedDate'
import OffsetDate from 'zoned-date/OffsetDate'

用法

ZonedDateOffsetDate在额外的时区支持下实现所有日期的方法。

  • OffsetDate:当您知道时区的偏移时。强烈建议您参加此课程。它只是数学和纯日期对象,并且总是有效。
  • ZonedDate:您以其名称指定时区。该库在内部使用Intl来得出偏移。特别是,ZonedDate明确支持DST,并全力支持Termporal proposal定义的歧义选项

注意:OffsetDateDate的子类(new OffsetDate instanceof Datetrue),而ZonedDate不是(new ZonedDate instanceof Datefalse)。

样本使用

const date = new OffsetDate('2020-01-01T03:00:00.000Z', {offset: 9})
console.log(date.hours) // return hours at GMT+9: 12
date.hours = 10 // set hours at GMT+9
date.hours = h => h - 1 // decrease by 1
console.log(date.toISOString()) // 2020-01-01T00:00:00.000Z

date.withMonth(1).withYear(y => y + 1) // returns a new OffsetDate object

时区转换

const date = new ZonedDate('2021-09-04T05:19:52.001', {timezone: 'Asia/Tokyo'}) // GMT+9
console.log(date.hours === 5)

date.timezone = 'Asia/Bangkok' // GMT+7
console.log(date.hours === 5 - 9 + 7)

date.timezone = 'UTC'
console.log(date.hours === 5 - 9 + 24)

date.timezone = 'America/New_York' // GMT-4
console.log(date.hours === 5 - 9 + -4 + 24)

DST支持

for (const [timezone, wallclock, disambiguation, expected] of [
    // positive dst
    // forward, dst starts
    ['Australia/ACT', '2023-10-01T02:00:00.000', undefined, 11],
    ['Australia/ACT', '2023-10-01T02:30:00.000', undefined, 11],
    ['Australia/ACT', '2023-10-01T02:30:00.000', 'compatible', 11],
    ['Australia/ACT', '2023-10-01T02:30:00.000', 'earlier', 10],
    ['Australia/ACT', '2023-10-01T02:30:00.000', 'later', 11],
    // backward, dst ends
    ['Australia/ACT', '2023-04-02T02:00:00.000', undefined, 11],
    ['Australia/ACT', '2023-04-02T02:30:00.000', undefined, 11],
    ['Australia/ACT', '2023-04-02T02:30:00.000', 'compatible', 11],
    ['Australia/ACT', '2023-04-02T02:30:00.000', 'earlier', 11],
    ['Australia/ACT', '2023-04-02T02:30:00.000', 'later', 10],

    // negative dst
    // forward, dst starts
    ['America/Los_Angeles', '2023-03-12T02:00:00.000', undefined, -7],
    ['America/Los_Angeles', '2023-03-12T02:30:00.000', undefined, -7],
    ['America/Los_Angeles', '2023-03-12T02:30:00.000', 'compatible', -7],
    ['America/Los_Angeles', '2023-03-12T02:30:00.000', 'earlier', -8],
    ['America/Los_Angeles', '2023-03-12T02:30:00.000', 'later', -7],
    // backward, dst ends
    ['America/Los_Angeles', '2023-11-05T01:00:00.000', undefined, -7],
    ['America/Los_Angeles', '2023-11-05T01:30:00.000', undefined, -7],
    ['America/Los_Angeles', '2023-11-05T01:30:00.000', 'compatible', -7],
    ['America/Los_Angeles', '2023-11-05T01:30:00.000', 'earlier', -7],
    ['America/Los_Angeles', '2023-11-05T01:30:00.000', 'later', -8],
]) {
    const date = new ZonedDate(wallclock, {timezone, disambiguation})
    console.assert(date.offset === expected)
    console.log('ok')
}

for (const [timezone, wallclock, disambiguation, expected] of [
    ['Australia/ACT', '2023-10-01T02:30:00.000', 'reject'],
    ['Australia/ACT', '2023-04-02T02:30:00.000', 'reject'],
    ['America/Los_Angeles', '2023-03-12T02:00:00.000', 'reject'],
    ['America/Los_Angeles', '2023-11-05T01:00:00.000', 'reject'],
]) {
    const date = new ZonedDate(wallclock, {timezone, disambiguation})
    try {
      date.time
    } catch (e) {
      console.log('ok')
      continue
    }
    console.log('failed')
}