Moment Timezone 文档

要使用 moment-timezone,你需要 moment@2.9.0+moment-timezone.jsmoment-timezone 数据。

¥To use moment-timezone, you will need moment@2.9.0+, moment-timezone.js, and the moment-timezone data.

为方便起见,在 momentjs.com/timezone/ 上提供了包含所有区域数据或数据子集的构建。

¥For convenience, there are builds available on momentjs.com/timezone/ with all the zone data or a subset of the data.

  • moment-timezone-with-data.js 建议用于服务器环境 (Node.js),涵盖所有可用年份。

    ¥moment-timezone-with-data.js is recommended for server environments (Node.js) and covers all years available.

  • moment-timezone-with-data-10-year-range.js 推荐用于大多数浏览器环境,涵盖从发布年份起 +/- 5 年。

    ¥moment-timezone-with-data-10-year-range.js is recommend for most browser environments, covering +/- 5 years from the year published.

  • moment-timezone-with-data-1970-2030.js 涵盖 60 年的范围,适用于那些需要更多数据但不需要完整数据文件的更大文件大小的人。

    ¥moment-timezone-with-data-1970-2030.js covers a 60 year range, for those that need more data but not the larger file size of the full data file.

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

¥If you use one of the above files, you still need moment.js, but you do not need moment-timezone.js because it is included.

Node.js

npm install moment-timezone

在 Node.js 中,所有数据都是预加载的。加载数据不需要额外的代码。

¥In Node.js, all the data is preloaded. No additional code is needed for loading data.

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

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

¥In ECMAScript native module format (or in TypeScript):

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

注意:你也不需要要求/导入基础 moment 库。Moment Timezone 会自动加载和扩展 moment 模块,然后返回修改后的实例。

¥Note: You don't need to require/import the base moment library as well. Moment Timezone will automatically load and extend the moment module, then return the modified instance.

npmyarn 这样的包管理器有时会造成安装多个版本的 moment 的情况。仅从 moment-timezone 导入有助于确保一致地使用相同的版本。请参阅 问题 #982 上的此意见 以获得更详细的解释,包括修复潜在版本控制问题的步骤。

¥Package managers like npm and yarn can sometimes create situations where multiple versions of moment are installed. Importing only from moment-timezone can help ensure that the same version is used consistently. See this comment on issue #982 for a much more detailed explanation, including steps to fix potential versioning problems.

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

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

预构建包 也包含在 npm 包中,可以直接加载。这些允许你导入具有较小数据子集的库。

¥The pre-built bundles are also included in the npm package, and can be loaded directly. These allow you to import the library with a smaller subset of data.

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

你也可以只导入没有任何预加载数据的库。

¥You can also import just the library without any preloaded data.

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 时,你需要加载数据和库。

¥When using Moment Timezone in the browser, you will need to load the data as well as the library.

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

¥You can either use the prebuilt library and data files linked on the homepage or build a subset of the data yourself and 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 包:

¥Note: By default, webpack bundles all moment-timezone data (in moment-timezone 0.5.25, that’s over 900 KBs minified). To strip out unwanted data and bundle only the zone and date range data you need, add the moment-timezone-data-webpack-plugin package:

// 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 部分

¥Alternatively, the pre-built bundles are also included in the npm package, and can be loaded directly. See the Node.js section for more details.

有关如何减少 Moment 的打包语言环境数据的示例,另请参阅主要的 Moment.js Webpack 文档。这些技术一起可以显着减少最终包的大小(缩小超过 1 MB,或缩小 85 KB + gzip)。

¥Also see the primary Moment.js Webpack documentation for an example of how to reduce Moment’s bundled locale data. Together these techniques can significantly reduce the final bundle size (by over 1 MB minified, or 85 KB minified + gzipped).

在 Moment.js 中使用时区有两个接口。

¥There are two interfaces for using time zones with Moment.js.

moment.tz(..., String) 在给定的时区进行解析

¥moment.tz(..., String) does parsing in given time zone

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

¥It takes all the same arguments as the moment constructor, but uses the last argument as a time zone identifier:

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 是在不同的时区创建的。

¥Note that created moments have different UTC time because these moments were created in different time zones.

moment().tz(String) 确实转换为提供的时区

¥moment().tz(String) does converting to provided time zone

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

¥In this example, you first create moment.utc("2013-11-18 11:55") object in UTC, and then change its timezone to specified. This also works if you create the object in your default timezone: moment("2013-11-18 11:55").

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

¥Note that created moments have equal UTC time because these moments were created in a default timezone.

在区域中解析

moment.tz(..., String);

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

¥The moment.tz constructor takes all the same arguments as the moment constructor, but uses the last argument as a time zone identifier.

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,并在解析时使用正确的偏移量。

¥This constructor is DST aware, and will use the correct offset when parsing.

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

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

¥The offset is only taken into consideration when constructing with an array, string without offset, or object.

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 转换为目标区域。

¥If the input string contains an offset, it is used instead for parsing. The parsed moment is then converted to the target zone.

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)

¥Unix timestamps and Date objects refer to specific points in time, thus it doesn't make sense to use the time zone offset when constructing. Using moment.tz(Number|Date, zone) is functionally equivalent to 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

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

¥Уou may specify a boolean right after format argument to use strict parsing. Strict parsing requires that the format and input match exactly, including delimeters.

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

解析歧义

由于夏令时,一个时间可能不存在,或者已经存在过两次。

¥Due to daylight saving time, there is a possibility that a time either does not exist, or has existed twice.

弹簧前进

¥Spring Forward

在春天,夏令时开始时,时钟向前移动一个小时。但实际上,不是时间在移动,而是偏移量在移动。

¥In the spring, at the start of DST, clocks move forward an hour. In reality though, it is not time that is moving, it is the offset moving.

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

¥Moving the offset forward gives the illusion that an hour has disappeared. As the clock ticks, you can see it move from 1:58 to 1:59 to 3:00. It is easier to see what is actually happening when you include the offset.

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

结果是 1:59:593:00:00 之间的任何时间实际上从未发生过。Moment Timezone 说明了这一点。如果你尝试解析一个不存在的时间,它将向前跳过 DST 间隔的量(通常为 1 小时)。

¥The result is that any time between 1:59:59 and 3:00:00 never actually happened. Moment Timezone accounts for this. If you try to parse a time that never existed, it will skip forward by the amount of the DST gap (usually 1 hour).

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

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

¥In this example, the two o'clock hour doesn't exist, so it is treated as equivalent to the three o'clock hour.

倒退

¥Fall Back

在秋天,夏令时结束时,时钟会向后拨一小时。同样,时间不会倒退,只有偏移量会倒退。在这种情况下,错觉是一个小时在重复。

¥In the fall, at the end of DST, clocks move backward an hour. Again, time is not moving backwards, only the offset is. In this case, the illusion is that an hour repeats itself.

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

¥Again, it is easier to see what is actually happening when you include the offset.

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

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

¥Moment Timezone handles this by always using the earlier instance of a duplicated hour.

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。

¥You won't be able to create a moment with the later instance of the duplicated hour unless you include the offset when parsing.

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 修改器将更改时区并更新偏移量。

¥The moment#tz mutator will change the time zone and update the offset.

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

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

¥This information is used consistently in other operations, like calculating the start of the day.

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

¥Without any argument, moment#tz returns:

  • 分配给 moment 实例的时区名称或

    ¥the time zone name assigned to the moment instance or

  • 如果未设置时区,则为 undefined

    ¥undefined if a time zone has not been set.

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 传递时,仅更新时区(和偏移量),保持本地时间不变。因此,如果偏移量发生变化,它现在将指向不同的时间点。

¥On passing a second parameter as true, only the timezone (and offset) is updated, keeping the local time same. Consequently, it will now point to a different point in time if the offset has changed.

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 还包含缩写时区名称的信息。

¥In addition to including the +00:00 formatting information, Moment Timezone also includes information for the abbreviated time zone name.

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 的地方之间的偏移量。

¥Note that these abbreviations may change depending on the time zone offset. This helps to distinguish offsets between places that may or may not use 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

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

¥Note also that these abbreviations are not globally unique. Below, you can see that both United States Central Standard Time and China Standard Time have the same abbreviation.

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 令牌时使用的。

¥You can also use moment#zoneAbbr to get the zone abbreviation. This is what moment.js uses when formatting the z token.

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

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

¥Moment.js also provides a hook for the long form time zone name. Because these strings are generally localized, Moment Timezone does not provide any long names for zones.

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

¥To provide long form names, you can override moment.fn.zoneName and use the zz token.

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 格式标记并不总是显示缩写的时区名称,而是显示每个区域的时间偏移。

¥Please note that the z formatting token will not always show the abbreviated time zone name, instead, will show the time offsets for each region.

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)。

¥By default, moment objects are created in the local time zone. The local time zone is determined by your JS environment such as a browser or server like Node.js.

要更改默认时区,请使用具有有效时区的 moment.tz.setDefault

¥To change the default time zone, use moment.tz.setDefault with a valid time zone.

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

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

¥To reset the default time zone to local, use moment.tz.setDefault with no arguments.

moment.tz.setDefault();

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

¥This is a global setting (shared by all modules).

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

¥Subsequent calls to moment.tz.setDefault will not affect existing moment objects or their clones.

猜测用户区域

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

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

¥Moment Timezone uses the Internationalization API (Intl.DateTimeFormat().resolvedOptions().timeZone) in supported browsers to determine the user's time zone.

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

¥On other browsers, time zone detection is rather tricky to get right, as there is little information provided by those browsers. For those, it will use Date#getTimezoneOffset and Date#toString on a handful of moments around the current year to gather as much information about the browser environment as possible. It then compares that information with all the time zone data loaded and returns the closest match. In case of ties, the time zone with the city with largest population is returned.

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

¥By default Moment Timezone caches the detected timezone. This means that subsequent calls to moment.tz.guess() will always return the same value.

你可以使用可选的布尔参数 "ignoreCache" 调用 moment.tz.guess()。如果设置为 true,缓存将被忽略并被新值覆盖。

¥You can call moment.tz.guess() with an optional boolean argument "ignoreCache". If set to true, the cache will be ignored and overwritten with the new value.

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

¥To get a list of all available time zone names, use 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()

¥To get a list of time zones for some country, use moment.tz.zonesForCountry().

moment.tz.zonesForCountry('US');

默认情况下,此方法返回按字母顺序排序的区域名称:

¥By default this method returns zone names sorted alphabetically:

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

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

¥To get also offsets, pass true as 2nd parameter:

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

它返回具有名称和偏移量的对象数组:

¥it returns array of objects with name and offset:

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

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

¥It's useful if you need to sort time zones by offset.

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

¥All country codes can be retrieved using method moment.tz.countries()

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

¥In order to match a timestamp to an offset, Moment Timezone uses a Zone object.

尽管你甚至不需要使用它,但该对象的构造函数在 moment.tz.Zone 命名空间中可用。

¥Though you shouldn't even need to use it, this object's constructor is available on the moment.tz.Zone namespace.

这个对象有 5 个属性。

¥This object has 5 properties.

{
    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 时区数据库命名指南

¥The uniquely identifying name of the time zone. See the IANA Time Zone database naming guidelines for more details about the naming convention.

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

¥Note that the guidelines also say that these zone identifiers shouldn't be displayed directly to end users:

没有经验的用户不应在没有帮助的情况下选择这些名称。分销商应提供文档和/或简单的选择接口,通过映射或 "捷克共和国" 等描述性文本而不是时区名称 "Europe/Prague" 来解释每个名称。

¥Inexperienced users are not expected to select these names unaided. Distributors should provide documentation and/or a simple selection interface that explains each name via a map or via descriptive text like "Czech Republic" instead of the timezone name "Europe/Prague".

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

¥Providing a full list of translated zone names for every locale is outside the scope of Moment Timezone. The Unicode CLDR project contains locale-aware mappings for this purpose.

缩写

zone.abbr(timestamp); // PST

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

¥Get the abbreviation for a given timestamp (in milliseconds) from a Zone.

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

偏移量

zone.utcOffset(timestamp); // 480

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

¥Get the offset for a given timestamp (in milliseconds) from a 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 的任意选择。因此,使用基于位置的标识符优于固定偏移标识符。

¥POSIX compatibility requires that the offsets are inverted. Therefore, Etc/GMT-X will have an offset of +X and Etc/GMT+X will have an offset of -X. This is a result of IANA's Time Zone Database and not an arbitrary choice by Moment.js. Thus, using locality based identifiers is preferred over fixed-offset identifiers.

数据库的维基百科条目 上也有描述:

¥This is also described on the Wikipedia entry for the database:

"Etc" 专区用于一些行政区,特别是 "Etc/UTC" 代表 协调世界时。为了符合 POSIX 风格,那些以 "Etc/GMT" 开头的区域名称的符号与标准的 ISO 8601 约定相反。在 "Etc" 区域,GMT 以西的区域名称为正号,东部区域名称为负号(例如,"Etc/GMT-14" 比 GMT 早 14 小时)。

¥The special area of "Etc" is used for some administrative zones, particularly for "Etc/UTC" which represents Coordinated Universal Time. In order to conform with the POSIX style, those zone names beginning with "Etc/GMT" have their sign reversed from the standard ISO 8601 convention. In the "Etc" area, zones west of GMT have a positive sign and those east have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours ahead of GMT).

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

¥For example, using the Europe/Madrid identifier gives a different result from 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 构造的时间戳的偏移量。

¥Parse an offset for a timestamp constructed from Date.UTC in that zone.

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

¥This is what Moment Timezone uses to parse input into a time zone. The process is conceptually similar to the following.

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

¥Assume we want to find the exact moment of March 19 2014 8:30 am in New York. Because the offset varies between -04:00 and -05:00 in New York, we don't know what the offset was on March 19th.

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

¥Instead, we create a timestamp in UTC and pass that to zone.parse, which will return the offset at that time.

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

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

¥This is the code that handles the cases referenced in the Parsing Ambiguities section above.

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 使用两种数据格式。用于计算的解压缩版本和用于缩小传输的打包版本。

¥Moment Timezone uses two data formats. An unpacked version for calculations and a packed version for minified transport.

解包格式

解压后的格式看起来与 区域对象 完全一样。

¥The unpacked format looks exactly like the zone object.

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

¥The data below is for Los Angeles between 2014 and 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 时才处于活动状态。

¥The lengths of abbrs, untils, offsets are all the same. The offset and abbr at any index are only active while the timestamp is less than the until at that index.

大声朗读此内容的一个简单方法是“在 untils[n-1]untils[n] 之间,缩写应为 abbrs[n],偏移量应为 offsets[n]”。

¥An easy way to read this aloud is "between untils[n-1] and untils[n], the abbr should be abbrs[n] and the offset should be offsets[n]".

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

¥Note that untils are measured in milliseconds and offsets are measured in minutes.

打包格式

打包格式表示单个字符串中的未打包区域。

¥The packed format represents an unpacked zone in a single string.

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

¥The data below is for Los Angeles between 2014 and 2018. More time zones can be seen in the packed source file.

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

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

¥In order to save as many bytes as possible, we used a very compact format to store the data.

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

¥The data is split into 6 sections separated by pipes.

#类型示例
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

名称:时区的规范名称。

¥Name: The canonical name of the time zone.

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

¥Abbr Map: A space separated list of all the abbreviations ever used in this time zone.

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

¥Offset Map: A space separated list of all the offsets ever used in this time zone in minutes in base 60.

缩写/偏移索引:offset 和 abbr 映射中紧密排列的索引数组。这些也在 base 60 中。

¥Abbr/Offset Index: A tightly packed array of indices into the offset and abbr maps. These are also in base 60.

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

¥Timestamp Diffs: This is where the timestamps are stored.

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

¥Because we are dealing with a sorted list of timestamps, we just store the diff from the last timestamps rather than storing the full timestamps.

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

¥The first item in the array is a unix timestamp in minutes. All items after the first item are numbers of minutes to be added to the previous value during unpacking. All items are stored in base 60.

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

¥As you may have seen from the example above, the timestamp diffs tend to duplicate the same values from year to year. These duplications allow gzip to compress the data even further than if we used full timestamps.

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

¥Population: The rough population size of the city that the zone is named after.

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

¥This is not in base 60, but instead uses scientific exponential notation. For example, a value of 15e6 means 15 * 106 (that's 15 with 6 zeros after it) and therefore represents the number 15,000,000.

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

¥The value is only used to compare nearly-identical zones when using the guess feature, so it doesn't need to be precise.

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

¥Note that this value might be empty for some zones.

基数 60?

¥Base 60?

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

¥You may be wondering why base 60 is used. Base 62 is a fairly common tool for ascii data compression, using a-z to represent 10-35 and A-Z to represent 36-61.

虽然使用 base 62 可能节省了几个字节,但 Moment Timezone 中的大部分数据都很好地映射到 60 的倍数。

¥While it may have saved a few bytes to use base 62, much of the data in Moment Timezone maps nicely to multiples of 60.

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

¥There are 60 minutes in an hour and 60 seconds in a minute. 3 hours is 30 minutes in base 60 and 300 seconds in base 60 instead of 180 and 10800 in base 10 or 2U and 2Oc in base 62.

链接格式

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

¥In order to reduce duplication, the Moment Timezone data packer will create links out of two zones that share data that is exactly the same.

此数据是由竖线分隔的两个区域名称。

¥This data is the two zone names separated by a pipe.

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。

¥Once the data has been packed and transported to the client, it must be added to Moment Timezone.

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

¥This happens automatically in Node.js and the pre-built bundles. If you're using a different loading method you might need to load the data yourself.

添加区域

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

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

¥To add zone data to Moment Timezone, use moment.tz.add.

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

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

¥To add more than one zone, pass an array of packed data.

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 源 以获取最新数据。

¥Note: The above zone data is sample data and is not up to date. Reference the moment-timezone source for up to date data.

添加链接

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

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

¥To link two zone names to the same data, use moment.tz.link.

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

¥The strings passed in should be in the link format: the two zone names separated by a pipe.

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

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

¥To add more than one link at a time, pass an array of link strings.

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

加载数据包

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

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

¥The data for Moment Timezone comes from the IANA Time Zone Database. New versions are released periodically as time zone laws change in various countries.

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

¥The versions are named after the year and an incrementing letter. 2014a 2014b 2014c...

为了将版本保持在一起,Moment Timezone 也有一个打包的对象格式。

¥In order to keep versions together, Moment Timezone has a bundled object format as well.

{
    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

¥To load a bundle into Moment Timezone, use moment.tz.load.

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

检查区域存在

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

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

¥To check if a zone exists, use moment.tz.zone. It will return the Zone if it was loaded and null if it was not loaded.

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

¥To get a list of all available time zone names, use moment.tz.names.

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

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

¥Because of the complexity of the packed and unpacked data formats, Moment Timezone has some heavily tested utility functions for working with the data.

解包数据的方法包含在核心库中,因为它们是使用该库所必需的。

¥Methods for unpacking data are included with the core library, as they are needed in order to use the library.

打包和子集化数据的方法包含在附加的 moment-timezone-utils.js 文件中。该文件向 moment.tz 命名空间添加了更多方法。

¥Methods for packing and subsetting the data are included in an additional moment-timezone-utils.js file. This file adds some more methods to the moment.tz namespace.

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

这会将 解压格式 中的数据转换为 打包格式

¥This converts data in the unpacked format to the 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

这会将 打包格式 中的数据转换为 解压格式

¥This converts data in the packed format to the 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 进制字符串。

¥Convert a base 10 number to a base 60 string.

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 接受精度位数的第二个参数。

¥Much like Number.prototype.toFixed, moment.tz.packBase60 accepts a second argument for the number of digits of precision.

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

小数点前一个单独的 0 被去掉。

¥A solitary 0 before the decimal point is dropped.

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

删除小数点后的尾随零。

¥Trailing zeroes after the decimal point are dropped.

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 为基数的数字。

¥Convert a base 60 string to a base 10 number.

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

为了减少重复,我们可以在共享数据的两个区域之外创建链接。

¥In order to reduce duplication, we can create links out of two zones that share data.

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 结合使用时特别有用,因为用于区分两个区域的旧规则可能不在过滤的年份范围内,从而允许将它们链接起来以节省空间。

¥This is especially useful when combined with moment.tz.filterYears, as older rules that would have differentiated two Zones may not be in the filtered year range, allowing them to be linked to save space.

过滤年份

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

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

¥By default, Moment Timezone includes all the data from the IANA Time Zone Database. This includes data from at least 1900 to 2038. Releases from version 0.5.37 onward include even more data, beyond the year 2400. The data for all these years may not be necessary for your use case.

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

¥moment.tz.filterYears can be used to filter out data for years outside a certain range.

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

如果只过了一年,它将用于开始和结束年份。

¥If only one year is passed, it will be used for the start and end year.

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

或者,其中一个较小的预制 主页上可用的包 可能已经满足你的需求。

¥Alternatively, one of the smaller pre-built bundles available on the homepage might already fit your needs.

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

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

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

¥The packing, link creation, and subsetting of years are all tools for compressing data to be transported to the client.

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

¥The moment.tz.filterLinkPack method combines all these into one simple interface. Pass in an unpacked bundle, start year, and end year and get a filtered, linked, packed bundle back.

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

¥This is what is being used to compress the output for the bundled data + library files on the homepage.