HTML 中使用的日期与时间格式
================

特定的 HTML 元素会使用日期和（或）时间值，指定这些值的字符串格式将在本篇文章中描述。

使用这些格式的元素包含一些令用户选择或指定日期、时间或日期和时间的 `<input>` 和 `<ins>`、`<del>` 元素，它们的 `datetime` 属性指定了插入或删除内容的日期或日期和时间。

对于 `<input>` 元素来说，能够返回包含代表日期或日期和时间的字符串 `value` 的 `type` 的值为：

* `date`
* `datetime-local`
* `month`
* `time`
* `week`
示例
--

在讨论日期和时间字符串如何在 HTML 中书写和解析的错综复杂的问题之前，这里有一些例子，应该可以让你很好地了解更常用的日期和时间字符串格式是什么样的。

示例 HTML 日期和时间字符串| 字符串 | 日期和（或）时间 |
| --- | --- |
| `2005-06-07` | 2005 年 6 月 7 日 | [详情] |
| `08:45` | 上午 8 时 45 分 | [详情] |
| `08:45:25` | 上午 8 时 45 分 25 秒 | [详情] |
| `0033-08-04T03:40` | 33 年 8 月 4 日，上午 3 时 40 分 | [详情] |
| `1977-04-01T14:00:30` | 1977 年 4 月 1 日，下午 2 时 00 分 30 秒 | [详情] |
| `1901-01-01T00:00Z` | 1901 年 1 月 1 日的半夜（UTC 时间） | [详情] |
| `1901-01-01T00:00:01-04:00` | 东部标准时间（EST）下 1901 年 1 月 1 日半夜经过 1 秒 | [详情] |

基本
--

在研究 HTML 元素所使用的与日期和时间有关的字符串的各种格式之前，了解关于它们的定义方式的一些基本事实是有帮助的。HTML 使用 ISO 8601 标准的一个变体，用于其日期和时间字符串。为了确保你的字符串实际上与 HTML 兼容，你值得查看你所使用的格式描述，因为 HTML 规范包括解析这些字符串的算法，实际上比 ISO 8601 更精确，所以在日期和时间字符串的预期外观上可能存在微妙的差异。

### 字符集

HTML 中的日期和时间总会使用 ASCII 字符集中的字符串。

### 年份数字

为了简化 HTML 中日期字符串的基本格式，规范要求所有年份都使用现代的公历表示法，虽然用户界面可能允许输入使用其他日历的日期，但基础值总是使用公历。

虽然公历直到 1582 年才创建（取代了类似的儒略历），但出于 HTML 的考虑，公历被延伸到了公元 1 年。确保任何较早的日期都考虑到了这一点。

就 HTML 日期而言，年份总是至少为四位数长度；1000 年之前的年份用前导零（“`0`”）填充，所以公元 72 年会记作 `0072`。这种写法不支持公元 1 年之前的年份，所以 HTML 不支持公元前 1 年（1 B.C.）或更早的年份。

除了**闰年**以外，一年通常是 365 天。

#### 闰年

**闰年**是指任何可以被 400 整除的年份*或者*是可以被 4 整除但不能被 100 整除的年份。尽管在日历上，每年通常为 365 天，但实际上地球完成绕太阳的一圈需要大约 365.2422 天。闰年有助于调整日历，使其与地球在其轨道上的实际位置保持同步。每四年增加一天，基本上使平均年长为 365.25 天，相当接近事实。

对算法的调整（当一年可以被 400 整除时，采取闰年；当一年可以被 100 整除时，跳过闰年）有助于使平均值更接近正确的天数（365.2425 天）。科学家们偶尔会认真地在日历上增加闰秒，以处理剩余的万分之三的天数，并补偿地球自转的逐渐自然减慢的情况。

每年的第二个月份，二月，一般含有 28 天，但会在闰年为 29 天。

### 一年中的第几月

一年中含有 12 个月，从 1 计数至 12。它们总是由一个两位数的 ASCII 字符串表示，其数值范围从 `01` 到 `12`。请参阅一月中的第几天一节中的表格，了解月份编号和它们相应的名称（以及天数长度）。

### 一月中的第几天

1、3、5、7、8、10 和 12 月份都有 31 天，4、6、9 和 11 月份都有 30 天，而 2 月份在大部分时间总会有 28 天，但在闰年中会有 29 天。详情如下表所示。

一年中的月份及每个月的长度| 月份编号 | 中文名称 | 每月所含天数 |
| --- | --- | --- |
| 01 | 一月 | 31 |
| 02 | 二月 | 28（闰年时为 29） |
| 03 | 三月 | 31 |
| 04 | 四月 | 30 |
| 05 | 五月 | 31 |
| 06 | 六月 | 30 |
| 07 | 七月 | 31 |
| 08 | 八月 | 31 |
| 09 | 九月 | 30 |
| 10 | 十月 | 31 |
| 11 | 十一月 | 30 |
| 12 | 十二月 | 31 |

星期字符串
-----

一个星期字符串指定一个特定年份中的特定星期。一个**有效的星期字符串**由一个有效的年份数字组成，后面是一个连字符（“`-`”，或 U+002D），然后是大写字母“`W`”（U+0057），再后面是该年的两位数的星期值。

一年中的周是一个介于 `01` 和 `53` 之间的两位数字符串。每一周从周一开始，周日结束。这意味着 1 月的前几天有可能被认为是上一周年的一部分，12 月的最后几天有可能被认为是下一周年的一部分。一年的第一周是指包含该年*第一个星期四的那一周*。例如，1953 年的第一个星期四是在 1 月 1 日，所以那一周——从 12 月 29 日星期一开始——被认为是一年的第一周。因此，1952 年 12 月 30 日发生在 `1953-W01` 周。

在这种情况下，一年含有 53 周：

* 日历年的第一天（1 月 1 日）是星期四**或**
* 日历年的第一天（1 月 1 日）是星期三，且该年为闰年

所有其他年份含有 52 周。

| 星期字符串 | 年份和星期数（日期区间） |
| --- | --- |
| `2001-W37` | 2001 年的第 37 周（2001 年 9 月 10-16 日） |
| `1953-W01` | 1953 年的第 1 周（1952 年 12 月 29 日 - 1953 年 1 月 4 日） |
| `1948-W53` | 1948 年的第 53 周（1948 年 12 月 27 日 - 1949 年 1 月 2 日） |
| `1949-W01` | 1949 年的第 1 周（1949 年 1 月 3 - 9 日） |
| `0531-W16` | 531 年的第 16 周（531 年 4 月 13 - 19 日） |
| `0042-W04` | 42 年的第 4 周（42 年 1 月 21 - 27 日） |

注意，年份和星期数都由前导零补齐长度，年份补齐至四位数，而星期数补齐至两位数。

月份字符串
-----

一个月份字符串代表特定的月份时间，而不是一年中的普通月份。也就是说，HTML 月份字符串不是代表“一月”，而是代表月份和年份的配对，比如“1972 年 1 月”。

一个 **有效的月份字符串** 由一个有效的年份数字（至少四位数的字符串）组成，后面是一个连字符（“`-`”，或 U+002D），再后面是一个两位数的月份数字，其中 `01` 代表一月，`12` 代表十二月。

| 月份字符串 | 年份和月 |
| --- | --- |
| `17310-09` | 17310 年 9 月 |
| `2019-01` | 2019 年 1 月 |
| `1993-11` | 1993 年 11 月 |
| `0571-04` | 571 年 4 月 |
| `0001-07` | 1 年 7 月 |

注意，每个年份至少为四位长度，少于四位的年份需要由前导零补齐位数。

日期字符串
-----

一个有效的日期字符串包含月份字符串，后面是一个连字符（“`-`”，或 U+002D），再后面是一个两位数的天数数字。

| 日期字符串 | 日期表示 |
| --- | --- |
| `1993-11-01` | 1993 年 11 月 1 日 |
| `1066-10-14` | 1066 年 10 月 14 日 |
| `0571-04-22` | 571 年 4 月 22 日 |
| `0062-02-05` | 62 年 2 月 5 日 |

时间字符串
-----

一个时间字符串可以指定一个精确到分、秒或毫秒的时间。不允许只指定小时或分钟。一个 **有效的时间字符串** 最少由一个两位数的小时和一个冒号（“`:`”，U+003A）组成，然后是一个两位数的分钟。分钟后面可以选择另一个冒号和一个两位数的秒数。可选的毫秒可以通过添加一个小数点字符（“`.`”，U+002E）和一个、两个或三个数字来指定。

这里有一些额外的基本规则：

* 小时总是 24 小时制，这意味着 `00` 代表半夜，11 PM 则为 `23`。不允许 `00`–`23` 范围以外的值出现。
* 分钟必须是 `00` 到 `59` 之间的两位数，不允许范围以外的值出现。
* 如果省略了秒数（即只指定精确到分钟的时间），则无需在分钟数后面跟随冒号。
* 如果指定了秒数，则其整数部分必须在 `00` 到 `59` 之间。你*不能*通过 `60` 或 `61` 这样的值来指定闰秒。
* 如果指定的秒数为整数，则不可在其后方跟随小数点。
* 如果秒数包含了小数，它可以是代表毫秒数的 1 至 3 位数，且跟随在时间字符串的秒成分之后的小数点后面。

| 时间字符串 | 时间 |
| --- | --- |
| `00:00:30.75` | 上午 12:00:30.75（午夜后 30.75 秒） |
| `12:15` | 下午 12:15 |
| `13:44:25` | 下午 1:44:25（下午 1:44 后 25 秒） |

本地日期时间字符串
---------

一个有效的 `datetime-local` 字符串由一个 `date` 字符串和一个 `time` 字符串连接起来，中间用字母“`T`”或空格分开。字符串中不包含时区的信息；日期和时间被认为是用户的本地时区。

当你设置 `datetime-local` 输入的 `value` 时，该字符串被**规范化**为标准形式。标准化的 `datetime` 字符串总是使用字母“`T`”来分隔日期和时间，并且字符串的时间部分尽可能地短。如果秒的值是 `:00`，则不使用秒的成分。


 有效的
 `datetime-local`
 字符串示例
 | 日期/时间字符串 | 标准化日期/时间字符串 | 实际日期和时间 |
| --- | --- | --- |
| `1986-01-28T11:38:00.01` | `1986-01-28T11:38:00.01` | 1986 年 1 月 28 日，上午 11:38:00.01 |
| `1986-01-28 11:38:00.010` | `1986-01-28T11:38:00.01`
注意，经过标准化后，该字符串与前一个 `datetime-local` 字符串相同。空格被“`T`”字符替换，秒数部分小数的尾随零被移除，令字符串更短。 | 1986 年 1 月 28 日，上午 11:38:00.01 |
| `0170-07-31T22:00:00` | `0170-07-31T22:00`
注意，该日期经过标准化后，去除了代表了秒数为零的“`:00`”，因为当秒数为零时，它是可选的，且标准化字符串要使得字符串尽可能更短。 | 170 年 7 月 31 日，下午 10:00 |

全局日期时间字符串
---------

全局日期和时间字符串指定了日期和时间，以及它所处的时区。一个**有效的全局日期和时间字符串**与本地日期时间字符串的格式相同，只是在时间后面附加了一个时区字符串。

### 时区偏移字符串

时区偏移字符串指定了与标准基准时间的正数或负数小时和分钟的偏移。有两种标准基准时间，它们非常接近于相同，但不完全相同：

* 对于 1960 年代初建立协调世界时（UTC）后的日期，时基是 `Z`，偏移量表示特定时区与经度 0º 的通过英国格林威治的皇家天文台的本初子午线的时间偏移量。
* 对于 UTC 之前的日期，时基是以 UT1 表示的，这是当代地球太阳时在本初子午线的时间。

时区字符串紧随日期和时间字符串中的时间之后。你可以指定“`Z`”作为时区偏移字符串，以表明时间是以 UTC 为单位的。否则，时区字符串的构造如下：

1. 表示偏移量的符号：加号（“`+`”，或 U+002B）表示本初子午线以东的时区，减号（“`-`”，或 U+002D）表示本初子午线以西的时区。
2. 该时区与本初子午线偏离的两位数小时数。这个值必须在 `00` 和 `23` 之间。
3. 可选的冒号字符（“`:`”）。
4. 偏离前述小时数的两位数分钟数；这个值必须在 `00` 和 `59` 之间。

虽然这种格式允许 -23:59 和 +23:59 之间的时区，但目前的时区偏移范围是 -12:00 到 +14:00，目前没有任何时区与小时的偏移是以 `00`、`30` 或 `45` 分钟以外的方式进行。这可能在任何时候都会发生变化，因为各国可以在任何时候以任何方式自由地改变其时区。

合法的全局日期时间字符串| 全局日期时间字符串 | 实际全局日期时间 | 本初子午线的日期和时间 |
| --- | --- | --- |
| `2005-06-07T00:00Z` | UTC 时间，2005 年 6 月 7 日半夜 | 2005 年 6 月 7 日半夜 |
| `1789-08-22T12:30:00.1-04:00` | 1789 年 8 月 22 日下午 12:30 经过十分之一秒，东部夏令时（EDT） | 1789 年 8 月 22 日下午 4:30 经过十分之一秒 |
| `3755-01-01 00:00+10:00` | 3755 年 1 月 1 日半夜，澳大利亚东部标准时间（AEST） | 3754 年 12 月 31 日下午 2:00 |

参见
--

* `<input>`
* `<ins>` 和 `<del>`：请查阅 `datetime` 属性，它指定了插入或删除内容的日期或本地日期和时间
* ISO 8601 定义
* JavaScript 指南中的数字和日期
* JavaScript `Date` 对象
* 以给定区域选项格式化日期和时间的 `Intl.DateTimeFormat` 对象