Moment 时区文档

要使用 moment-timezone,您需要[email protected]+moment-timezone.jsmoment-timezone数据。

为了方便,momentjs.com/timezone/ 上提供了包含所有时区数据或部分数据的构建。

  • moment-timezone-with-data.js推荐用于服务器环境(Node.js),并且涵盖了所有可用的年份。
  • moment-timezone-with-data-10-year-range.js推荐用于大多数浏览器环境,涵盖了发布年份前后 +/- 5 年。
  • moment-timezone-with-data-1970-2030.js涵盖了 60 年的范围,适用于需要更多数据但不需要完整数据文件的大文件大小的用户。

如果您使用上述文件之一,您仍然需要moment.js,但您不需要moment-timezone.js,因为它已包含在内。

Node.js

编辑
npm install moment-timezone

在 Node.js 中,所有数据都是预加载的。加载数据无需其他代码。

var moment = require('moment-timezone');
moment().tz("America/Los_Angeles").format();

在 ECMAScript 原生模块格式(或在 TypeScript)中

import moment from 'moment-timezone';
moment().tz("America/Los_Angeles").format();

注意:您无需同时 require/import 基础 moment 库。Moment Timezone 将自动加载和扩展 moment 模块,然后返回修改后的实例。

诸如 npmyarn 之类的包管理器有时会创建安装了多个 moment 版本的情况。moment-timezone 导入有助于确保始终使用同一版本。请参阅 问题 #982 上的此评论 以获取更详细的解释,包括修复潜在版本问题步骤。

// Unnecessary, can cause issues with package managers
import moment from 'moment';
import 'moment-timezone';

// Correct
import moment from 'moment-timezone';

npm 包中还包含 预构建包,并且可以直接加载。这些包允许您使用较小的数据子集导入库。

import moment from 'moment-timezone/builds/moment-timezone-with-data-10-year-range.js'; // or .min.js

您还可以仅导入库,而无需任何预加载数据。

import moment from 'moment-timezone/moment-timezone.js'; // or .min.js
moment.tz.load(customData);

浏览器

编辑
<script src="moment.js"></script>
<script src="moment-timezone-with-data.js"></script>

在浏览器中使用 Moment Timezone 时,您需要加载数据和库。

您可以使用 主页 上链接的预构建库和数据文件,或自己构建数据子集并 加载 数据。

moment().tz("America/Los_Angeles").format();

Require.js

编辑
require.config({
    paths: {
        "moment": "path/to/moment"
    }
});
define(["path/to/moment-timezone-with-data"], function (moment) {
    moment().tz("America/Los_Angeles").format();
});

Webpack

编辑
npm install moment-timezone
var moment = require('moment-timezone');
moment().tz("America/Los_Angeles").format();

注意:默认情况下,webpack 会捆绑所有 moment-timezone 数据(在 moment-timezone 0.5.25 中,已缩小为 900 KB 以上)。若要剔除不需要的数据并仅捆绑您需要的时区和日期范围数据,请添加 moment-timezone-data-webpack-plugin

// webpack.config.js
const MomentTimezoneDataPlugin = require('moment-timezone-data-webpack-plugin');
const currentYear = new Date().getFullYear();

module.exports = {
    plugins: [
        // To include only specific zones, use the matchZones option
        new MomentTimezoneDataPlugin({
            matchZones: /^America/
        }),

        // To keep all zones but limit data to specific years, use the year range options
        new MomentTimezoneDataPlugin({
            startYear: currentYear - 5,
            endYear: currentYear + 5,
        }),
    ],
};

或者,npm 包中还包含 预构建包,并且可以直接加载。有关更多详细信息,请参阅 Node.js 部分

另请参阅主要 Moment.js Webpack 文档,了解如何减少 Moment 的捆绑区域设置数据。这些技术结合使用可以显著减少最终的捆绑大小(缩小后超过 1 MB,或缩小和 gzip 压缩后为 85 KB)。

有两个接口可用于将时区与 Moment.js 一起使用。

moment.tz(..., String) 执行在给定时区中解析

它采用与 moment 构造函数相同的所有参数,但将最后一个参数用作时区标识符

var a = moment.tz("2013-11-18 11:55", "Asia/Taipei");
var b = moment.tz("2013-11-18 11:55", "America/Toronto");

a.format(); // 2013-11-18T11:55:00+08:00
b.format(); // 2013-11-18T11:55:00-05:00

a.utc().format(); // 2013-11-18T03:55Z
b.utc().format(); // 2013-11-18T16:55Z

请注意,创建的时刻具有不同的 UTC 时间,因为这些时刻是在不同的时区创建的。

moment().tz(String) 执行转换到提供的时区

var a = moment.utc("2013-11-18 11:55").tz("Asia/Taipei");
var b = moment.utc("2013-11-18 11:55").tz("America/Toronto");

a.format(); // 2013-11-18T19:55:00+08:00
b.format(); // 2013-11-18T06:55:00-05:00

a.utc().format(); // 2013-11-18T11:55Z
b.utc().format(); // 2013-11-18T11:55Z

在此示例中,您首先在 UTC 中创建 moment.utc("2013-11-18 11:55") 对象,然后将其时区更改为指定的时区。如果您在默认时区创建对象,此操作同样有效:moment("2013-11-18 11:55")

请注意,创建的时刻具有相等的 UTC 时间,因为这些时刻是在 默认时区 中创建的。

在时区中解析

编辑
moment.tz(..., String);

moment.tz 构造函数采用与 moment 构造函数相同的所有参数,但将最后一个参数用作 时区标识符

var a = moment.tz("2013-11-18 11:55", "America/Toronto");
var b = moment.tz("May 12th 2014 8PM", "MMM Do YYYY hA", "America/Toronto");
var c = moment.tz(1403454068850, "America/Toronto");
a.format(); // 2013-11-18T11:55:00-05:00
b.format(); // 2014-05-12T20:00:00-04:00
c.format(); // 2014-06-22T12:21:08-04:00

此构造函数支持 DST,并且在解析时将使用正确的偏移量。

moment.tz("2013-12-01", "America/Los_Angeles").format(); // 2013-12-01T00:00:00-08:00
moment.tz("2013-06-01", "America/Los_Angeles").format(); // 2013-06-01T00:00:00-07:00

仅在使用数组、不带偏移量的字符串或对象构造时才考虑偏移量。

var arr = [2013, 5, 1],
    str = "2013-12-01",
    obj = { year : 2013, month : 5, day : 1 };

moment.tz(arr, "America/Los_Angeles").format(); // 2013-06-01T00:00:00-07:00
moment.tz(str, "America/Los_Angeles").format(); // 2013-12-01T00:00:00-08:00
moment.tz(obj, "America/Los_Angeles").format(); // 2013-06-01T00:00:00-07:00

moment.tz(arr, "America/New_York").format();    // 2013-06-01T00:00:00-04:00
moment.tz(str, "America/New_York").format();    // 2013-12-01T00:00:00-05:00
moment.tz(obj, "America/New_York").format();    // 2013-06-01T00:00:00-04:00

如果输入字符串包含偏移量,则在解析时将使用该偏移量。然后将解析的时刻转换为目标时区。

var zone = "America/Los_Angeles";
moment.tz('2013-06-01T00:00:00',       zone).format(); // 2013-06-01T00:00:00-07:00
moment.tz('2013-06-01T00:00:00-04:00', zone).format(); // 2013-05-31T21:00:00-07:00
moment.tz('2013-06-01T00:00:00+00:00', zone).format(); // 2013-05-31T17:00:00-07:00

Unix 时间戳和 Date 对象引用特定时间点,因此在构造时使用时区偏移量没有意义。使用 moment.tz(Number|Date, zone) 在功能上等同于 moment(Number|Date).tz(zone)

var timestamp = 1403454068850,
    date = new Date(timestamp);

moment.tz(timestamp, "America/Los_Angeles").format(); // 2014-06-22T09:21:08-07:00
moment(timestamp).tz("America/Los_Angeles").format(); // 2014-06-22T09:21:08-07:00

moment.tz(date, "America/Los_Angeles").format();      // 2014-06-22T09:21:08-07:00
moment(date).tz("America/Los_Angeles").format();      // 2014-06-22T09:21:08-07:00

您可以在格式参数后指定一个布尔值,以使用严格解析。严格解析要求格式和输入完全匹配,包括分隔符

moment.tz('It is 2012-05-25', 'YYYY-MM-DD', "America/Toronto").isValid();       // true 
moment.tz('It is 2012-05-25', 'YYYY-MM-DD', true, "America/Toronto").isValid(); // false
moment.tz('2012-05-25', 'YYYY-MM-DD', true, "America/Toronto").isValid();       // true
moment.tz('2012-05.25', 'YYYY-MM-DD', true, "America/Toronto").isValid();       // false

解析歧义

编辑

由于夏时制,有可能某个时间不存在或存在两次。

春季前进

在春季,夏时制开始时,时钟向前移动一小时。然而实际上,移动的不是时间,而是偏移量。

向前移动偏移量会给人一种一小时消失的错觉。随着时钟滴答作响,您可以看到它从1:58移动到1:59再到3:00。当您包括偏移量时,更容易看到实际发生的情况。

1:58 -5
1:59 -5
3:00 -4
3:01 -4

结果是,1:59:593:00:00之间的任何时间实际上从未发生过。Moment Timezone 考虑到了这一点。如果您尝试解析从未存在的时间,它将向前跳过夏时制差距的时间量(通常为 1 小时)。

moment.tz("2012-03-11 01:59:59", "America/New_York").format() // 2012-03-11T01:59:59-05:00
moment.tz("2012-03-11 02:00:00", "America/New_York").format() // 2012-03-11T03:00:00-04:00
moment.tz("2012-03-11 02:59:59", "America/New_York").format() // 2012-03-11T03:59:59-04:00
moment.tz("2012-03-11 03:00:00", "America/New_York").format() // 2012-03-11T03:00:00-04:00

在此示例中,两点钟不存在,因此将其视为等效于三点钟。

秋季后退

在秋季,夏时制结束时,时钟向后移动一小时。同样,时间不会向后移动,只有偏移量会移动。在这种情况下,错觉是一小时重复自身。

同样,当您包括偏移量时,更容易看到实际发生的情况。

1:58 -4
1:59 -4
1:00 -5
1:01 -5

Moment Timezone 通过始终使用重复小时的较早实例来处理此问题。

moment.tz("2012-11-04 00:59:59", "America/New_York"); // 2012-11-04T00:59:59-04:00
moment.tz("2012-11-04 01:00:00", "America/New_York"); // 2012-11-04T01:00:00-04:00
moment.tz("2012-11-04 01:59:59", "America/New_York"); // 2012-11-04T01:59:59-04:00
moment.tz("2012-11-04 02:00:00", "America/New_York"); // 2012-11-04T02:00:00-05:00

除非您在解析时包括偏移量,否则您将无法使用重复小时的较晚实例创建时刻。

moment.tz("2012-11-04 01:00:00-04:00", "America/New_York"); // 2012-11-04T01:00:00-04:00
moment.tz("2012-11-04 01:00:00-05:00", "America/New_York"); // 2012-11-04T01:00:00-05:00

转换为时区

编辑
moment().tz(String);
moment().tz(String, Boolean);

moment#tz变异器将更改时区并更新偏移量。

moment("2013-11-18").tz("America/Toronto").format('Z'); // -05:00
moment("2013-11-18").tz("Europe/Berlin").format('Z');   // +01:00

此信息在其他操作中始终如一地使用,例如计算一天的开始时间。

var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.format();                     // 2013-11-18T11:55:00-05:00
m.startOf("day").format();      // 2013-11-18T00:00:00-05:00
m.tz("Europe/Berlin").format(); // 2013-11-18T06:00:00+01:00
m.startOf("day").format();      // 2013-11-18T00:00:00+01:00

如果没有参数,moment#tz将返回

  • 分配给时刻实例的时区名称或
  • 如果尚未设置时区,则返回undefined
var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.tz();  // America/Toronto
var m = moment.tz("2013-11-18 11:55");
m.tz() === undefined;  // true

将第二个参数传递为true时,仅更新时区(和偏移量),保持本地时间不变。因此,如果偏移量已更改,它现在将指向时间中的不同点。

var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.format();                           // 2013-11-18T11:55:00-05:00
m.tz('Europe/Berlin', true).format()  // 2013-11-18T11:55:00+01:00

格式化附加项

编辑
moment.tz(String).format("Z z"); // -08:00 PST
moment.tz(String).zoneAbbr();    // PST
moment.tz(String).zoneName();    // PST

除了包括+00:00格式化信息外,Moment Timezone 还包括缩写时区名称的信息。

moment.tz([2012, 0], 'America/New_York').format('z');    // EST
moment.tz([2012, 5], 'America/New_York').format('z');    // EDT
moment.tz([2012, 0], 'America/Los_Angeles').format('z'); // PST
moment.tz([2012, 5], 'America/Los_Angeles').format('z'); // PDT

请注意,这些缩写可能会根据时区偏移量而改变。这有助于区分可能使用或不使用夏时制的地区之间的偏移量。

// Denver observes DST
moment.tz([2012, 0], 'America/Denver').format('Z z');  // -07:00 MST
moment.tz([2012, 5], 'America/Denver').format('Z z');  // -06:00 MDT
// Phoenix does not observe DST
moment.tz([2012, 0], 'America/Phoenix').format('Z z'); // -07:00 MST
moment.tz([2012, 5], 'America/Phoenix').format('Z z'); // -07:00 MST

另请注意,这些缩写不是全局唯一的。在下面,您可以看到美国中部标准时间和中国标准时间都具有相同的缩写。

moment.tz('2016-01-01', 'America/Chicago').format('z');    // CST
moment.tz('2016-01-01', 'Asia/Shanghai').format('z');      // CST

您还可以使用moment#zoneAbbr来获取时区缩写。这是 moment.js 在格式化z标记时使用的内容。

moment.tz([2012, 0], 'America/New_York').zoneAbbr(); // EST
moment.tz([2012, 5], 'America/New_York').zoneAbbr(); // EDT

Moment.js 还为长格式时区名称提供了一个挂钩。由于这些字符串通常是本地化的,因此 Moment Timezone 不会为时区提供任何长名称。

要提供长格式名称,您可以覆盖moment.fn.zoneName并使用zz标记。

var abbrs = {
    EST : 'Eastern Standard Time',
    EDT : 'Eastern Daylight Time',
    CST : 'Central Standard Time',
    CDT : 'Central Daylight Time',
    MST : 'Mountain Standard Time',
    MDT : 'Mountain Daylight Time',
    PST : 'Pacific Standard Time',
    PDT : 'Pacific Daylight Time',
};

moment.fn.zoneName = function () {
    var abbr = this.zoneAbbr();
    return abbrs[abbr] || abbr;
};

moment.tz([2012, 0], 'America/New_York').format('zz');    // Eastern Standard Time
moment.tz([2012, 5], 'America/New_York').format('zz');    // Eastern Daylight Time
moment.tz([2012, 0], 'America/Los_Angeles').format('zz'); // Pacific Standard Time
moment.tz([2012, 5], 'America/Los_Angeles').format('zz'); // Pacific Daylight Time

请注意,z格式化标记不会总是显示缩写时区名称,而是会显示每个区域的时间偏移量。

moment.tz('America/Los_Angeles').format('z')  // "PDT"     (abbreviation)
moment.tz('Asia/Magadan').format('z')         // "+11"     (3-char offset)
moment.tz('Asia/Colombo').format('z')         // "+0530"   (5-char offset)

默认时区

编辑
moment.tz.setDefault(String);

默认情况下,moment对象是在本地时区创建的。本地时区由您的 JS 环境(例如浏览器或像 Node.js 这样的服务器)决定。

要更改默认时区,请使用moment.tz.setDefault和一个有效时区。

moment.tz.setDefault("America/New_York");

要将默认时区重置为本地,请使用不带参数的moment.tz.setDefault

moment.tz.setDefault();

这是一个全局设置(由所有模块共享)。

随后对moment.tz.setDefault的调用不会影响现有的moment对象或它们的克隆。

猜测用户时区

编辑
moment.tz.guess();
moment.tz.guess(Boolean);

Moment Timezone 使用国际化 API(Intl.DateTimeFormat().resolvedOptions().timeZone)在受支持的浏览器中确定用户的时区。

在其他浏览器中,时区检测很难做到正确,因为这些浏览器提供的信息很少。对于这些浏览器,它将在当前年份周围的几个时刻使用 Date#getTimezoneOffsetDate#toString 来尽可能多地收集有关浏览器环境的信息。然后,它将该信息与加载的所有时区数据进行比较,并返回最接近的匹配项。如果出现平局,则返回人口最多的城市所在时区。

默认情况下,Moment Timezone 会缓存检测到的时区。这意味着对 moment.tz.guess() 的后续调用始终会返回相同的值。

您可以使用可选布尔参数“ignoreCache”调用 moment.tz.guess()。如果设置为 true,则将忽略缓存并用新值覆盖它。

moment.tz.guess(); // America/Chicago
// suppose the client's timezone changes to Europe/Berlin
moment.tz.guess(); // America/Chicago
moment.tz.guess(true); // Europe/Berlin
moment.tz.guess(); // Europe/Berlin

获取所有时区

编辑
moment.tz.names(); // String[]

要获取所有可用时区名称的列表,请使用 moment.tz.names

moment.tz.names(); // ["Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", ...]

获取国家/地区的时区

编辑
moment.tz.zonesForCountry(String); // String[]
moment.tz.zonesForCountry(String, Boolean);

要获取某个国家/地区的时区列表,请使用 moment.tz.zonesForCountry()

moment.tz.zonesForCountry('US');

默认情况下,此方法按字母顺序返回时区名称

["America/Adak", "America/Anchorage", ... "Pacific/Honolulu"]

要同时获取偏移量,请将 true 作为第二个参数传递

moment.tz.zonesForCountry('CN', true);

它返回包含名称和偏移量的对象数组

[
   { name: "Asia/Shanghai", offset: -480 },
   { name: "Asia/Urumqi", offset: -360 }
]

如果您需要按偏移量对时区进行排序,这将很有用。

可以使用 moment.tz.countries() 方法检索所有国家/地区代码

为了将时间戳与偏移量匹配,Moment Timezone 使用 Zone 对象。

虽然您甚至不需要使用它,但此对象的构造函数在 moment.tz.Zone 命名空间中可用。

此对象有 5 个属性。

{
    name       : 'America/Los_Angeles',          // the unique identifier
    abbrs      : ['PDT', 'PST'],                 // the abbreviations
    untils     : [1414918800000, 1425808800000], // the timestamps in milliseconds
    offsets    : [420, 480],                     // the offsets in minutes
    population : 15000000                        // a rough population count for the largest city in this zone
}

名称

编辑
zone.name; // America/Los_Angeles

时区的唯一标识名称。有关命名约定的更多详细信息,请参阅 IANA 时区数据库命名指南

请注意,该指南还指出,这些时区标识符不应直接显示给最终用户

没有经验的用户不应指望在没有帮助的情况下选择这些名称。分销商应提供文档和/或一个简单的选择界面,通过地图或描述性文本(例如“捷克共和国”)而不是时区名称 “欧洲/布拉格” 来解释每个名称。

为每个语言环境提供翻译的时区名称的完整列表超出了 Moment Timezone 的范围。Unicode CLDR 项目 包含用于此目的的语言环境感知映射。

缩写

编辑
zone.abbr(timestamp); // PST

Zone 获取给定时间戳(以毫秒为单位)的缩写。

moment.tz.zone('America/Los_Angeles').abbr(1403465838805); // PDT
moment.tz.zone('America/Los_Angeles').abbr(1388563200000); // PST

偏移量

编辑
zone.utcOffset(timestamp); // 480

Zone 获取给定时间戳(以毫秒为单位)的偏移量。

moment.tz.zone('America/Los_Angeles').utcOffset(1403465838805); // 420
moment.tz.zone('America/Los_Angeles').utcOffset(1388563200000); // 480

POSIX 兼容性要求偏移量被反转。因此,Etc/GMT-X 的偏移量为 +X,而 Etc/GMT+X 的偏移量为 -X。这是 IANA 的 时区数据库 的结果,而不是 Moment.js 的任意选择。因此,首选使用基于位置的标识符,而不是固定偏移量标识符。

这也描述在 数据库的维基百科条目

“Etc” 的特殊区域用于一些行政区域,特别是“Etc/UTC”,它表示 协调世界时。为了符合 POSIX 样式,那些以“Etc/GMT”开头的时区名称与标准 ISO 8601 惯例的符号相反。在“Etc”区域中,格林威治时间以西的时区名称中带有正号,而以东的时区名称中带有负号(例如“Etc/GMT-14”比格林威治时间早 14 小时)。

例如,使用 Europe/Madrid 标识符给出的结果与 Etc/GMT+1 不同。

moment().tz('Etc/GMT+1').format('YYYY-MM-DD HH:mm ZZ');
// '2014-12-18 11:22 -0100'
moment().tz('Europe/Madrid').format('YYYY-MM-DD HH:mm ZZ');
// '2014-12-18 13:22 +0100'

解析偏移量

编辑
zone.parse(timestamp); // 480

解析在该时区中从 Date.UTC 构造的时间戳的偏移量。

这是 Moment Timezone 用于将输入解析为时区的方式。该过程在概念上类似于以下过程。

假设我们想找到纽约时间“2014 年 3 月 19 日上午 8:30”的确切时刻。由于纽约的偏移量在 -04:00-05:00 之间变化,因此我们不知道 3 月 19 日的偏移量是多少。

相反,我们在 UTC 中创建一个时间戳并将其传递给 zone.parse,它将返回该时间点的偏移量。

var zone = moment.tz.zone('America/New_York');
zone.parse(Date.UTC(2012, 2, 19, 8, 30)); // 240

这是处理上述 解析歧义 部分中引用的案例的代码。

var zone = moment.tz.zone('America/New_York');
zone.parse(Date.UTC(2012, 2, 11, 1, 59)); // 300
zone.parse(Date.UTC(2012, 2, 11, 2, 0)); // 240

Moment Timezone 使用两种数据格式。一种是用于计算的未打包版本,另一种是用于精简传输的打包版本。

未打包格式

编辑

未打包格式看起来完全像 时区对象

以下数据适用于 2014 年至 2018 年之间的洛杉矶。

{
    name       : 'America/Los_Angeles',
    abbrs      : ['PST', 'PDT','PST', 'PDT', 'PST', 'PDT', 'PST', 'PDT', 'PST', 'PDT', 'PST'],
    untils     : [1394359200000, 1414918800000, 1425808800000, 1446368400000, 1457863200000, 1478422800000, 1489312800000, 1509872400000, 1520762400000, 1541322000000, null],
    offsets    : [480, 420, 480, 420, 480, 420, 480, 420, 480, 420, 480],
    population : 15000000,
    countries  : ['US']
}

abbrs、untils、offsets 的长度都相同。当时间戳小于该索引处的 until 时,任何索引处的 offsetabbr 才处于活动状态。

大声朗读它的简单方法是“在 untils[n-1]untils[n] 之间,abbr 应为 abbrs[n],offset 应为 offsets[n]

请注意,untils 以毫秒为单位测量,而 offsets 以分钟为单位测量。

打包格式

编辑

打包格式以单个字符串表示未打包的时区。

以下数据适用于 2014 年至 2018 年之间的洛杉矶。可以在 打包源文件 中看到更多时区。

'America/Los_Angeles|PST PDT|80 70|01010101010|1Lzm0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0|15e6'

为了尽可能节省字节,我们使用非常紧凑的格式来存储数据。

数据被分成 6 个部分,用竖线分隔。

#类型示例
0名称America/Los_Angeles
1缩写映射PST PDT
2偏移量映射80 70
3缩写/偏移量索引01010101010
4时间戳差异1Lzm0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0
5人口15e6

名称:时区的规范名称。

缩写映射:此时区中曾经使用过的所有缩写的空格分隔列表。

偏移量映射:此时区中曾经使用过的所有偏移量的空格分隔列表,以 60 为基数的分钟为单位。

缩写/偏移量索引:紧密打包的偏移量和缩写映射索引数组。这些也以 60 为基数。

时间戳差异:时间戳存储在此处。

由于我们处理的是排序的时间戳列表,因此我们仅存储最后一个时间戳的差异,而不是存储完整的时间戳。

数组中的第一个项目是 Unix 时间戳(以分钟为单位)。第一个项目之后的所有项目都是解包期间要添加到前一个值中的分钟数。所有项目都存储在 60 进制中。

正如您从上面的示例中看到的那样,时间戳差异往往会逐年重复相同的值。这些重复使 gzip 能够将数据压缩得比使用完整时间戳时更进一步。

人口:以区域命名的城市的粗略人口规模。

这不是 60 进制,而是使用科学指数表示法。例如,15e6 的值表示 15 * 106(即 15 后面有 6 个零),因此表示数字 15,000,000

该值仅用于在使用 猜测功能 时比较近乎相同的区域,因此它不需要精确。

请注意,对于某些区域,此值可能为空。

60 进制?

您可能想知道为什么使用 60 进制。62 进制是 ascii 数据压缩中相当常见的工具,使用 a-z 表示 10-35,使用 A-Z 表示 36-61

虽然使用 62 进制可以节省一些字节,但 Moment Timezone 中的大部分数据都可以很好地映射到 60 的倍数。

一小时有 60 分钟,一分钟有 60 秒。3 小时在 60 进制中为 30 分钟,在 60 进制中为 300 秒,而不是 10 进制中的 18010800,也不是 62 进制中的 2U2Oc

链接格式

编辑

为了减少重复,Moment Timezone 数据打包器将创建两个共享完全相同数据的区域的链接。

此数据是由管道分隔的两个区域名称。

moment.tz.add('America/Los_Angeles|PST PDT|80 70|01010101010|1Lzm0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0');
moment.tz.link('America/Los_Angeles|US/Pacific');
moment.tz("2013-12-01", "America/Los_Angeles").format(); // 2013-12-01T00:00:00-08:00
moment.tz("2013-12-01", "US/Pacific").format();          // 2013-12-01T00:00:00-08:00

一旦数据打包并传输到客户端,就必须将其添加到 Moment Timezone。

这在 Node.js 和 预构建包 中自动发生。如果您使用的是其他加载方法,则可能需要自己加载数据。

添加区域

编辑
moment.tz.add(PackedZoneString)
moment.tz.add(PackedZoneString[])

要将区域数据添加到 Moment Timezone,请使用 moment.tz.add

moment.tz.add('America/Los_Angeles|PST PDT|80 70|0101|1Lzm0 1zb0 Op0');

要添加多个区域,请传递打包数据的数组。

moment.tz.add([
    'America/Los_Angeles|PST PDT|80 70|0101|1Lzm0 1zb0 Op0',
    'America/New_York|EST EDT|50 40|0101|1Lz50 1zb0 Op0'
]);

注意:上述区域数据是示例数据,并非最新数据。请参考 moment-timezone 源 以获取最新数据。

添加链接

编辑
moment.tz.link(PackedLinkString)
moment.tz.link(PackedLinkString[])

要将两个区域名称链接到相同的数据,请使用 moment.tz.link

传入的字符串应采用 链接格式:由管道分隔的两个区域名称。

moment.tz.link('America/Los_Angeles|US/Pacific');

要一次添加多个链接,请传递链接字符串数组。

moment.tz.link([
    'America/Los_Angeles|US/Pacific',
    'America/New_York|US/Eastern'
]);

加载数据包

编辑
moment.tz.load({
    zones : [],
    links : [],
    version : '2014e'
});

Moment Timezone 的数据来自 IANA 时区数据库。随着各国时区法律的变化,会定期发布新版本。

版本以年份和增量字母命名。2014a 2014b 2014c...

为了保持版本的一致性,Moment Timezone 也有一个捆绑对象格式。

{
    version : '2014e',
    zones : [
        'America/Los_Angeles|PST PDT|80 70|0101|1Lzm0 1zb0 Op0',
        'America/New_York|EST EDT|50 40|0101|1Lz50 1zb0 Op0'
    ],
    links : [
        'America/Los_Angeles|US/Pacific',
        'America/New_York|US/Eastern'
    ]
}

要将包加载到 Moment Timezone,请使用 moment.tz.load

moment.tz.load({
    version : '2014e',
    zones : [...],
    links : [...]
})

检查区域是否存在

编辑
moment.tz.zone(name); // Zone or null

要检查区域是否存在,请使用 moment.tz.zone。如果已加载,它将返回区域;如果未加载,则返回 null

moment.tz.zone("UnloadedZone"); // null
moment.tz.add("UnloadedZone|UZ|0|0|");
moment.tz.zone("UnloadedZone"); // Zone { name : "UnloadedZone", ...}

获取区域名称

编辑
moment.tz.names(); // String[]

要获取所有可用时区名称的列表,请使用 moment.tz.names

moment.tz.names(); // ["Africa/Abidjan", "Africa/Accra", "Africa/Addis_Ababa", ...]

由于打包和解包数据格式的复杂性,Moment Timezone 有一些经过大量测试的实用功能,用于处理数据。

解包数据的方法包含在核心库中,因为使用库需要这些方法。

用于打包和子集化数据的函数包含在附加的 moment-timezone-utils.js 文件中。此文件向 moment.tz 命名空间添加了一些函数。

// in moment-timezone.js
moment.tz.unpack
moment.tz.unpackBase60
// in moment-timezone-utils.js
moment.tz.pack
moment.tz.packBase60
moment.tz.createLinks
moment.tz.filterYears
moment.tz.filterLinkPack

打包

编辑
moment.tz.pack(UnpackedObject); // PackedString

此函数将 未打包格式 中的数据转换为 打包格式

var unpacked = {
    name       : 'Indian/Mauritius',
    abbrs      : ['LMT', 'MUT', 'MUST', 'MUT', 'MUST', 'MUT'],
    offsets    : [-230, -240, -300, -240, -300, -240],
    untils     : [-1988164200000, 403041600000, 417034800000, 1224972000000, 1238274000000, null],
    population : 150000
};
moment.tz.pack(unpacked); // "Indian/Mauritius|LMT MUT MUST|-3O -40 -50|012121|-2xorO 34unO 14L0 12kr0 11z0|15e4"

解包

编辑
moment.tz.unpack(PackedString); // UnpackedObject

此函数将 打包格式 中的数据转换为 未打包格式

var packed = "Indian/Mauritius|LMT MUT MUST|-3O -40 -50|012121|-2xorO 34unO 14L0 12kr0 11z0|15e4";

moment.tz.unpack(packed);
// {
//     name       : 'Indian/Mauritius',
//     abbrs      : ['LMT', 'MUT', 'MUST', 'MUT', 'MUST', 'MUT'],
//     offsets    : [-230, -240, -300, -240, -300, -240],
//     untils     : [-1988164200000, 403041600000, 417034800000, 1224972000000, 1238274000000, null],
//     population : 150000
// };

打包为 60 进制

编辑
moment.tz.packBase60(Number); // Base60String

将 10 进制数转换为 60 进制字符串。

moment.tz.packBase60(9);    // 9
moment.tz.packBase60(10);   // a
moment.tz.packBase60(59);   // X
moment.tz.packBase60(1337); // mh

Number.prototype.toFixed 类似,moment.tz.packBase60 接受第二个参数,用于指定精度位数。

moment.tz.packBase60(1.1667,   1); // 1.a
moment.tz.packBase60(20.12345, 3); // k.7op
moment.tz.packBase60(59,       1); // X

小数点前的单个 0 会被丢弃。

moment.tz.packBase60(1.1667, 1); // 1.a
moment.tz.packBase60(0.1667, 1); // .a

小数点后的尾随零会被丢弃。

moment.tz.packBase60(1/6, 1); // .a
moment.tz.packBase60(1/6, 5); // .a
moment.tz.packBase60(59, 5);  // X

解包 60 进制

编辑
moment.tz.unpackBase60(Base60String); // Number

将 60 进制字符串转换为 10 进制数。

moment.tz.unpackBase60('9');     // 9
moment.tz.unpackBase60('a');     // 10
moment.tz.unpackBase60('X');     // 59
moment.tz.unpackBase60('mh');    // 1337
moment.tz.unpackBase60('1.9');   // 1.15
moment.tz.unpackBase60('k.7op'); // 20.123449074074074

创建链接

编辑
moment.tz.createLinks(UnpackedBundle); // UnpackedBundle

为了减少重复,我们可以使用共享数据的两个时区创建链接。

var unlinked = {
    zones : [
        {name:"Zone/One",abbrs:["OST","ODT"],offsets:[60,120],untils:[403041600000,417034800000]},
        {name:"Zone/Two",abbrs:["OST","ODT"],offsets:[60,120],untils:[403041600000,417034800000]}
    ],
    links : [],
    version : "2014x-doc-example"
};

moment.tz.createLinks(unlinked);

{
    zones : [
        {name:"Zone/One",abbrs:["OST","ODT"],offsets:[60,120],untils:[403041600000,417034800000]}
    ],
    links : ["Zone/One|Zone/Two"],
    version : "2014x-doc-example"
}

当与 moment.tz.filterYears 结合使用时,此功能特别有用,因为可能区分两个时区的较旧规则可能不在过滤的年份范围内,从而允许将它们链接起来以节省空间。

过滤年份

编辑
moment.tz.filterYears(UnpackedZone, Number, Number); // UnpackedZone

默认情况下,Moment Timezone 包含 IANA 时区数据库 中的所有数据。其中包括至少从 1900 年到 2038 年的数据。从版本 0.5.37 开始的版本包含更多数据,超过 2400 年。所有这些年份的数据可能并不适用于你的用例。

moment.tz.filterYears 可用于过滤掉特定范围之外年份的数据。

var all    = { name : "America/Los_Angeles", abbrs : [...], offsets : [...] untils : [...]};
var subset = moment.tz.filterYears(all, 2012, 2016);
all.untils.length;    // 186
subset.untils.length; // 11

如果只传递一年,它将用作开始年份和结束年份。

var all    = { name : "America/Los_Angeles", abbrs : [...], offsets : [...] untils : [...]};
var subset = moment.tz.filterYears(all, 2012);
all.untils.length;    // 186
subset.untils.length; // 3

或者,主页上提供的较小的预构建包 之一可能已经满足你的需求。

过滤年份、创建链接和打包

编辑
moment.tz.filterLinkPack(UnpackedBundle, Number, Number); // PackedBundle

打包、链接创建和年份子集化都是用于压缩要传输到客户端的数据的工具。

moment.tz.filterLinkPack 方法将所有这些功能组合到一个简单的界面中。传入一个未打包的包、开始年份和结束年份,然后获取一个经过过滤、链接和打包的包。

这是用于压缩 主页上的捆绑数据 + 库文件 的输出。