在 HTML 中使用日期和時間格式

某些 HTML 元素使用日期和/或時間值。本文將介紹指定這些值的字串格式。

使用此類格式的元素包括某些形式的 <input> 元素,它們允許使用者選擇或指定日期、時間或兩者,以及 <ins><del> 元素,它們的 datetime 屬性指定內容插入或刪除的日期或日期和時間。

對於 <input>,其 value 包含表示日期和/或時間的字串的輸入 type 值是:

示例

在深入探討 HTML 中日期和時間字串的編寫和解析的複雜性之前,這裡有一些示例,它們應該能讓你很好地瞭解更常用的日期和時間字串格式是什麼樣的。

HTML 日期和時間字串示例
String 日期和/或時間
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 年或更早的年份。

一年通常為 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 之間的兩位數字字串。每週從週一開始,到週日結束。這意味著一月份的前幾天可能被認為是上一個週年的組成部分,而十二月份的最後幾天可能被認為是下一個週年的組成部分。一年中的第一個周是包含當年第一個星期四的周。例如,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。不允許使用 00 - 23 範圍之外的值。
  • 分鐘必須是介於 0059 之間的兩位數。不允許使用該範圍之外的值。
  • 如果省略秒數(以指定僅精確到分鐘的時間),則分鐘數後不應有冒號。
  • 如果指定,秒數的整數部分必須介於 0059 之間。您不能透過使用 6061 等值來指定閏秒。
  • 如果指定了秒數並且是整數,則其後不得有小數點。
  • 如果包含秒的小數部分,它可能是一到三位數字長,表示毫秒數。它位於時間字串的秒元件後的小數點之後。
時間字串 時間
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

全球日期和時間字串

全域性日期和時間字串指定日期和時間以及它發生的時區。有效全域性日期和時間字串的格式與本地日期和時間字串相同,只是在時間之後附加了一個時區字串。

時區偏移字串

時區偏移字串指定與標準時間基準相差的小時和分鐘數的正負偏移量。有兩個標準時間基準,它們非常接近,但不完全相同:

  • 對於 20 世紀 60 年代初協調世界時 (UTC) 建立後的日期,時間基準是 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 升級到更新版本,並將您的硬體升級到 x86_64 或 IA64。如果您仍然使用其他硬體,您可以嘗試在 32 位虛擬機器中模擬 64 位硬體,但大多數 VM 不支援這種虛擬化,因為穩定性可能會受到影響,並且效能肯定會大大降低。

Y10k 問題(通常在客戶端)

在許多伺服器中,日期儲存為數字而不是字串——固定大小的數字,與格式無關(除了位元組序)。在 10,000 年之後,這些數字只會比以前大一點,所以許多伺服器不會在 10,000 年之後提交的表單中看到問題。

問題在於客戶端:解析年份中包含超過 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 問題將在您去世幾個世紀後發生,為什麼要擔心它呢?正是因為您將已經去世,所以使用您的軟體的公司將不得不繼續使用您的軟體,而沒有其他程式設計師足夠了解系統來修復它。

另見