HTML 中使用的日期和时间格式

某些 HTML 元素使用日期和/或时间值。本文介绍了指定这些值的字符串的格式。

使用此类格式的元素包括 <input> 元素的某些形式,这些形式允许用户选择或指定日期、时间或两者,以及 <ins><del> 元素,它们的 datetime 属性指定插入或删除内容发生的日期或日期和时间。

对于 <input>type 输入的值,其 value 包含表示日期和/或时间的字符串是

示例

在深入研究 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 1901年1月1日东部标准时间(EST)午夜过后1秒 [详细信息]

基础

在查看 HTML 元素使用的各种日期和时间相关字符串格式之前,了解它们定义方式的一些基本事实会很有帮助。HTML 使用ISO 8601标准的变体来表示其日期和时间字符串。值得查看您使用的格式的描述,以确保您的字符串确实与 HTML 兼容,因为 HTML 规范包含用于解析这些字符串的算法,实际上比 ISO 8601 更精确,因此在日期和时间字符串的预期外观方面可能存在细微差异。

字符集

HTML 中的日期和时间始终是使用ASCII字符集的字符串。

年份数字

为了简化 HTML 中日期字符串使用的基本格式,规范要求所有年份都使用现代(或**推算**)公历。虽然用户界面可能允许使用其他日历输入日期,但底层值始终使用公历。

虽然公历直到 1582 年才创建(取代了类似的儒略历),但为了 HTML 的目的,公历被扩展回公元 1 年。确保任何更早的日期都考虑了这一点。

为了 HTML 日期,年份始终至少为四位数长;公元 1000 年之前的年份用前导零(“0”)填充,因此公元 72 年写为 0072。公元 1 年之前的年份不受支持,因此 HTML 不支持公元前 1 年(公元前 1 年)或更早的年份。

一年通常为 365 天,除了在**闰年**期间。

闰年

**闰年**是指任何能被 400 整除的年份,或者年份能被 4 整除但不能被 100 整除。尽管日历年通常为 365 天,但地球实际上大约需要 365.2422 天才能绕太阳完成一次轨道。闰年有助于调整日历,使其与地球在其轨道上的实际位置同步。每四年在一年中添加一天,实际上使平均年份为 365.25 天,这接近正确。

对算法的调整(当年份可以被 400 整除时采用闰年,而当年份可以被 100 整除时跳过闰年)有助于使平均值更接近正确的日期数(365.2425 天)。科学家偶尔会在日历中添加闰秒(认真地说),以处理剩下的千分之三天的误差,并补偿地球自转逐渐自然发生的减速。

虽然月份 02,二月,通常有 28 天,但在闰年有 29 天。

一年中的月份

一年有 12 个月,从 1 到 12 编号。它们始终由两位数的 ASCII 字符串表示,其值范围从 0112。请参阅每月天数部分中的表格,了解月份数字及其对应的名称(以及天数)。

每月的天数

月份数字 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)以及两位数的年份周值组成。

年份周是介于 0153 之间的两位数字符串。每个星期从星期一开始,到星期天结束。这意味着 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 年一月”。

**有效的月份字符串**由一个有效的年份数字(至少四位数的字符串)、一个连字符(“-”或 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 点为 23。不允许 0023 范围之外的任何值。
  • 分钟必须是介于 0059 之间的两位数。不允许该范围之外的任何值。
  • 如果省略秒数(仅指定精确到分钟的时间),冒号不应该跟随分钟数。
  • 如果指定了秒数并且是整数,则后面不应跟随小数点。
  • 如果指定了秒数并且是整数,则后面不应跟随小数点。
  • 如果包含了秒数的小数部分,它可以是一到三位数字长,表示毫秒数。它位于时间字符串秒数部分之后的小数点之后。
时间字符串 时间
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

全局日期和时间字符串

全球日期和时间字符串指定日期和时间以及发生的时区。**有效的全球日期和时间字符串**与本地日期和时间字符串的格式相同,只是在时间之后附加了一个时区字符串,位于时间之后。

时区偏移字符串

时区偏移字符串指定从标准时间基线正负小时和分钟的偏移量。有两个标准时间基线,它们非常接近,但并不完全相同

  • 对于协调世界时(UTC)在 1960 年代初建立后的日期,时间基线为 Z,偏移量表示特定时区相对于 0º 经线(经过英国格林威治皇家天文台)的子午线时间的偏移量。
  • 对于 UTC 之前的日期,时间基线则用UT1表示,它是子午线上的当代地球太阳时间。

时区字符串立即附加在日期和时间字符串中的时间之后。您可以指定“Z”作为时区偏移字符串,以指示时间以 UTC 指定。否则,时区字符串将按如下方式构造

  1. 一个表示偏移量符号的字符:加号(“+”或 U+002B)表示位于子午线以东的时区,减号(“-”或 U+002D)表示位于子午线以西的时区。
  2. 一个两位数表示该时区相对于子午线的偏移小时数。此值必须介于 0023 之间。
  3. 可选的冒号(":")字符。
  4. 两位数的分钟数,表示超过小时的分钟数;该值必须介于 0059 之间。

虽然此格式允许时区在 -23:59 到 +23:59 之间,但当前时区偏移范围为 -12:00 到 +14:00,并且当前没有时区偏离小时数以外的任何其他值,例如 003045 分钟。这可能会随时发生变化,因为国家/地区可以随时以任何他们希望的方式更改其时区。

有效全局日期和时间字符串的示例
全局日期和时间字符串 实际全局日期和时间 本初子午线上的日期和时间
2005-06-07T00:00Z 2005 年 6 月 7 日,协调世界时(UTC)午夜 2005 年 6 月 7 日,午夜
1789-08-22T12:30:00.1-04:00 1789 年 8 月 22 日,东部夏令时(EDT)下午 12:30 十分之一秒 1789 年 8 月 22 日,下午 4:30 十分之一秒
3755-01-01 00:00+10:00 3755 年 1 月 1 日,澳大利亚东部标准时间(AEST)午夜 3754 年 12 月 31 日,下午 2:00

日期问题

由于数据存储和精度问题,您可能需要了解一些客户端和服务器端问题。

Y2K38 问题(通常是服务器端)

JavaScript 使用双精度浮点数存储日期,与所有数字一样,这意味着 JavaScript 代码不会遇到 Y2K38 问题,除非使用整数强制转换/位黑客,因为所有 JavaScript 位运算符都使用 32 位带符号的 2 的补码整数。

问题在于服务器端:存储大于 2^31 - 1 的日期。要解决此问题,您必须使用无符号 32 位整数、带符号 64 位整数或双精度浮点数在服务器上存储所有日期。如果您的服务器是用 PHP 编写的,解决方法可能很简单,只需升级到 PHP 8 或 7,并将硬件升级到 x86_64 或 IA64。如果您仍然使用其他硬件,可以尝试在 32 位虚拟机中模拟 64 位硬件,但大多数虚拟机不支持这种虚拟化,因为稳定性可能会受到影响,性能肯定会大幅下降。

Y10K 问题(通常是客户端)

在许多服务器中,日期存储为数字而不是字符串——固定大小的数字,与格式无关(除了字节序)。在公元 10000 年之后,这些数字将比以前略大一些,因此许多服务器不会看到在公元 10000 年之后提交的表单的问题。

问题在于客户端:解析年份中包含超过 4 位数字的日期。

html
<!--midnight of January 1st, 10000: the exact time of Y10K-->
<input type="datetime-local" value="+010000-01-01T05:00" />

就这么简单。只需为任意位数的数字做好准备。不要只为 5 位数字做好准备。以下是用编程方式设置值的 JavaScript 代码

js
function setValue(element, date) {
  const isoString = date.toISOString();
  element.value = isoString.substring(0, isoString.indexOf("T") + 6);
}

为什么要担心 Y10K 问题,因为它将在您去世后几个世纪才发生?正是因为您已经去世了,因此使用您的软件的公司将被迫继续使用您的软件,而没有其他程序员能够充分了解该系统来修复它。

另请参见