Moment Timezone 文档

要使用 moment-timezone,您需要 moment@2.9.0+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();

注意:您也不需要要求/导入基础 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 时,您需要加载数据和库。

您可以使用 the homepage 上链接的预建库和数据文件,也可以自己和 load it 构建数据的子集。

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时区数据(在moment时区 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 的捆绑语言环境数据的示例,另请参阅主要的 Moment.js Webpack 文档。 这些技术一起可以显着减少最终包的大小(缩小超过 1 MB,或缩小 85 KB + gzip)。

在 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

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

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

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

在区域中解析

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

如果输入字符串包含偏移量,则将其用于解析。 然后将解析的moment转换为目标区域。

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 说明了这一点。 如果您尝试解析一个不存在的时间,它将向前跳过 DST 间隔的量(通常为 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。

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 返回:

  • 分配给moment实例的时区名称或
  • 如果未设置时区,则为 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

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

// 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) 来确定用户的时区。

在其他浏览器上,时区检测很难正确进行,因为这些浏览器提供的信息很少。 对于那些,它将在今年左右的几个moment使用 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 时区数据库命名指南

请注意,准则还指出这些区域标识符不应直接显示给最终用户:

没有经验的用户不应在没有帮助的情况下选择这些名称。 经销商应提供 文档和/或一个简单的选择界面,通过地图或通过 像 "捷克共和国" 这样的描述性文本,而不是时区名称 "Europe/Prague"

为每个语言环境提供完整的翻译区域名称列表超出了 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" 开头的区域名称的符号与标准的 国际标准化组织 8601 约定相反。 在 "Etc" 区域,GMT 以西的区域名称为正号,东部区域名称为负号(例如,"Etc/GMT-14" 比 GMT 早 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 用来将输入解析为时区的内容。 该过程在概念上类似于以下内容。

假设我们想要找到 March 19 2014 8:30 am 在纽约的确切moment。 因为纽约的 -04:00-05:00 之间的偏移量不同,所以我们不知道 3 月 19 日的偏移量是多少。

相反,我们在 UTC 中创建时间戳并将其传递给 zone.parsezone.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 使用两种数据格式。 用于计算的解压缩版本和用于缩小传输的打包版本。

解包格式

解压后的格式看起来与 zone object 完全一样。

以下数据适用于 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的长度都是一样的。 任何索引处的 offsetabbr 仅在时间戳小于该索引处的 until 时才处于活动状态。

大声朗读的一种简单方法是 "在 untils[n-1]untils[n] 之间,缩写应为 abbrs[n],偏移量应为 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 为基数)。

Abbr/Offset Index: 紧密排列的索引数组到偏移和缩略图。 这些也在 base 60 中。

时间戳差异:这是存储时间戳的地方。

因为我们正在处理一个排序的时间戳列表,所以我们只存储与最后一个时间戳的差异,而不是存储完整的时间戳。

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

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

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

不是以 60 为基数,而是使用科学指数计数法。 例如,值 15e6 表示 15 * 106 (即 15 后面有 6 个零)因此代表数字 15,000,000

该值仅用于在使用 guess feature 时比较几乎相同的区域,因此不需要精确。

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

基数 60?

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

虽然使用 base 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

传入的字符串应该在 link format 中: 由管道分隔的两个区域名称。

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。 如果已加载,它将返回 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

这会将 unpacked format 中的数据转换为 packed format

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

这会将 packed format 中的数据转换为 unpacked format

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
// };

打包 Base 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

解包 Base 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 方法将所有这些组合到一个简单的界面中。 传入一个未打包的包、开始年份和结束年份,然后返回一个过滤、链接、打包的包。

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