小巧、快速、可靠。
擇三。
日期與時間函數

1. 概述

SQLite 支援以下七個純量日期和時間函數

  1. date(時間值, 修飾詞, 修飾詞, ...)
  2. time(時間值, 修飾詞, 修飾詞, ...)
  3. datetime(時間值, 修飾詞, 修飾詞, ...)
  4. julianday(時間值, 修飾詞, 修飾詞, ...)
  5. unixepoch(時間值, 修飾詞, 修飾詞, ...)
  6. strftime(格式, 時間值, 修飾詞, 修飾詞, ...)
  7. timediff(時間值, 時間值)

前六個日期和時間函數接受一個可選的時間值作為參數,後跟零個或多個修飾詞。strftime() 函數也將格式字串作為其第一個參數。timediff() 函數正好接受兩個參數,它們都是時間值

SQLite 沒有專用的日期/時間資料類型。日期和時間值可以儲存為以下任何一種格式:

ISO-8601 符合 ISO 8601 日期/時間值的文字字串。範例:'2025-05-29 14:16:00'
儒略日數 自 -4713-11-24 12:00:00 以來的天數,包含小數天數。範例:2460825.09444444
Unix 時間戳記 自 1970-01-01 00:00:00 以來的秒數,包含小數秒數。範例:1748528160

這三種格式統稱為時間值。所有日期時間函數都接受 ISO-8601 文字或儒略日數作為時間值。通過添加可選的修飾詞參數 'auto''unixepoch',它們也可以接受 Unix 時間戳記。由於 timediff() 函數不接受修飾詞,因此它只能使用 ISO-8601 和儒略日數時間值。

date() 函數以 YYYY-MM-DD 格式返回日期文字。

time() 函數以 HH:MM:SS 格式返回時間文字,如果使用subsec 修飾詞,則格式為 HH:MM:SS.SSS。

datetime() 函數以 YYYY-MM-DD HH:MM:SS 格式返回日期和時間,如果使用subsec 修飾詞,則格式為 YYYY-MM-DD HH:MM:SS.SSS。

julianday() 函數返回儒略日 - 自公元前 4714 年 11 月 24 日格林威治時間中午以來的天數(包含小數天數)(公曆)。

unixepoch() 函數返回 Unix 時間戳記 - 自 1970-01-01 00:00:00 UTC 以來的秒數。unixepoch() 函數通常返回整數秒數,但使用可選的subsec 修飾詞時,它將返回小數秒數。

strftime() 函數根據指定為第一個參數的格式字串返回格式化的日期。格式字串支援標準 C 函式庫中strftime() 函數中最常見的替代,以及兩個新的替代:%f 和 %J。以下是截至 3.46.0 版 (2024-05-23) 的有效 strftime() 替代的完整列表。早期版本的 SQLite 可能不支援所有替代。如果看到未定義或不支援的替代,則結果為 NULL。

%d月份中的日期:01-31
%e月份中的日期(不含前導零):1-31
%f小數秒數:SS.SSS
%FISO 8601 日期格式:YYYY-MM-DD
%G對應 %V 的 ISO 8601 年份
%g對應 %V 的 ISO 8601 年份(兩位數)
%H小時:00-24
%I12 小時制的小時:01-12
%j一年中的第幾天:001-366
%J儒略日數(含小數)
%k小時(不含前導零):0-24
%l%I(不含前導零):1-12
%m月份:01-12
%M分鐘:00-59
%p根據小時顯示「AM」或「PM」
%P根據小時顯示「am」或「pm」
%RISO 8601 時間格式:HH:MM
%s自 1970-01-01 以來的秒數
%S秒數:00-59
%TISO 8601 時間格式:HH:MM:SS
%U一年中的第幾週 (00-53) - 第 01 週從第一個星期日開始
%u星期幾 1-7,星期一為 1
%VISO 8601 標準的星期數
%w星期幾 0-6,星期日為 0
%W一年中的第幾週 (00-53) - 第 01 週從第一個星期一開始
%Y年份:0000-9999
%% %

其他日期和時間函數可以用 strftime() 表示

函數等效的 strftime()
date(...)strftime('%F', ...)
time(...)strftime('%T', ...)
datetime(...)strftime('%F %T', ...)
julianday(...) CAST(strftime('%J', ...) as REAL)
unixepoch(...) CAST(strftime('%s', ...) as INT)

date()、time() 和 datetime() 函數都返回文字,因此它們的 strftime() 等效函數是完全相同的。 然而,julianday() 和 unixepoch() 函數返回數值。它們的 strftime() 等效函數返回一個字串,該字串是對應數字的文字表示形式。

提供 strftime() 以外函數的主要原因是為了方便和效率。 julianday() 和 unixepoch() 函數分別返回實數值和整數值,並且不會產生使用 '%J' 或 '%s' 格式說明符與 strftime() 函數所導致的格式轉換成本或不準確性。

timediff(A,B) 函數返回一個字串,描述為了達到時間 A 需要添加到 B 的時間量。timediff() 結果的格式設計為易於閱讀。格式為

(+|-)YYYY-MM-DD HH:MM:SS.SSS

此時間差字串也是其他日期/時間函數的允許修飾符。以下不變量適用於時間值 A 和 B

datetime(A) = datetime(B, timediff(A,B))

月份和年份的長度有所不同。二月比三月短。閏年比非閏年長。timediff() 的輸出會將所有這些都考慮在內。timediff() 函數旨在提供時間跨度的易於理解的描述。如果您想知道兩個日期 A 和 B 之間的天數或秒數,則可以隨時執行以下操作之一

SELECT julianday(B) - julianday(A);
SELECT unixepoch(B) - unixepoch(A);

即使對於跨越不同天數的值 A 和 B,timediff(A,B) 也可能返回相同的結果 - 取決於起始日期。 例如,以下兩個 timediff() 呼叫都返回相同的結果(“-0000-01-00 00:00:00.000”),即使第一個時間跨度為 28 天,第二個時間跨度為 31 天

SELECT timediff('2023-02-15','2023-03-15');
SELECT timediff('2023-03-15','2023-04-15');

總結:如果您想要易於理解的時間跨度,請使用 timediff()。 如果您想要精確的時間差(以天或秒為單位),請使用兩個 julianday() 或 unixepoch() 呼叫之間的差值。

2. 時間值

時間值可以採用以下任何格式。 該值通常是一個字串,但在格式 12 的情況下,它可以是一個整數或浮點數。

  1. YYYY-MM-DD
  2. YYYY-MM-DD HH:MM
  3. YYYY-MM-DD HH:MM:SS
  4. YYYY-MM-DD HH:MM:SS.SSS
  5. YYYY-MM-DDTHH:MM
  6. YYYY-MM-DDTHH:MM:SS
  7. YYYY-MM-DDTHH:MM:SS.SSS
  8. HH:MM
  9. HH:MM:SS
  10. HH:MM:SS.SSS
  11. now
  12. DDDDDDDDDD

格式 5 到 7 中,「T」是一個用於分隔日期和時間的字元,如同 ISO-8601 標準的要求。格式 8 到 10 僅指定時間,預設日期為 2000-01-01。格式 11,字串「now」,會被轉換為目前的日期和時間,其值取自使用中 sqlite3_vfs 物件的 xCurrentTime 方法。「now」作為日期和時間函式的參數,在同一個 sqlite3_step() 呼叫中的多次使用,總是會返回完全相同的值。日期和時間使用 協調世界時 (UTC)。格式 12 是以整數或浮點數表示的 儒略日。如果格式 12 後面緊跟著 「auto」「unixepoch」 修飾符,則它也可能被解釋為 Unix 時間戳記。

格式 2 到 10 之後可以選擇性地加上時區指示符,格式為「[+-]HH:MM」或僅為「Z」。日期和時間函式內部使用 UTC 或「Zulu」時間,因此「Z」後綴表示不進行時區調整。任何非零的「HH:MM」後綴會從指示的日期和時間中減去,以便計算 Zulu 時間。例如,以下所有時間值都是等效的:

2013-10-07 08:23:19.120
2013-10-07T08:23:19.120Z
2013-10-07 04:23:19.120-04:00
2456572.84952685

在格式 4、7 和 10 中,小數秒值 SS.SSS 在小數點後可以有一位或多位數字。範例中正好顯示三位數字,因為只有前三位數字對結果有效,但輸入字串可以少於或多於三位數字,日期/時間函式仍然可以正常運作。同樣地,格式 12 顯示了 10 位有效數字,但日期/時間函式實際上會接受表示儒略日所需的任意位數。

除了 timediff() 函式之外,所有函式中的時間值(以及所有修飾符)都可以省略,在這種情況下,會假設時間值為「now」。

3. 修飾符

除了 timediff() 之外,所有日期/時間函式的時間值參數後面都可以跟著零個或多個修飾符,這些修飾符會更改日期和/或時間。每個修飾符都是應用於其左側時間值的轉換。修飾符從左到右應用;順序很重要。可用的修飾符如下:

  1. NNN 天
  2. NNN 小時
  3. NNN 分鐘
  4. NNN 秒
  5. NNN 個月
  6. NNN 年
  7. ±HH:MM
  8. ±HH:MM:SS
  9. ±HH:MM:SS.SSS
  10. ±YYYY-MM-DD
  11. ±YYYY-MM-DD HH:MM
  12. ±YYYY-MM-DD HH:MM:SS
  13. ±YYYY-MM-DD HH:MM:SS.SSS
  14. ceiling (無條件進位)
  15. floor (無條件捨去)
  16. start of month (月初)
  17. start of year (年初)
  18. start of day (本日開始)
  19. weekday N (星期 N)
  20. unixepoch (Unix 紀元)
  21. julianday (儒略日)
  22. auto (自動)
  23. localtime (本地時間)
  24. utc (UTC 時間)
  25. subsec (毫秒)
  26. subsecond (毫秒)

前十三個修飾符(1 到 13)將指定的時間量添加到其左側參數指定的日期和時間。修飾符 1 到 6 名稱結尾的「s」字元是可選的。NNN 值可以是任何浮點數,可以選擇性地加上「+」或「-」前綴。

**時間偏移修飾符**(7 到 13) 將時間值移動指定的年、月、日、小時、分鐘和/或秒數。格式 10 到 13 需要起始的「+」或「-」,但格式 7、8 和 9 則為可選。更改從左到右應用。首先將年份偏移 YYYY,然後將月份偏移 MM,然後將日期偏移 DD,依此類推。timediff(A,B) 函式以格式 13 返回時間偏移,將時間值 B 偏移到 A。

由於一個月或一年的長度會隨著月份或年份而變化,因此在日期加上月份和/或年份時,可能會產生歧義。例如,2024-02-29 後一年是哪一天?是 2025-02-28 還是 2025-03-01?或者 2023-12-31 後兩個月是哪一天?是 2024-02-29 還是 2024-03-02?對於如何解決這種歧義沒有共識,因此可以使用「無條件進位」(ceiling,修飾詞 14)和「無條件捨去」(floor,修飾詞 15)修飾詞,讓程式設計師自行決定。如果時間位移後的下一個修飾詞是「無條件進位」,則日期中的任何歧義都會解析為較晚的日期。「無條件捨去」修飾詞則會將歧義解析為前一個月的最後一天。預設行為是「無條件進位」。

起始」(start of,修飾詞 16 到 18)修飾詞會將日期回溯到目標月份、年份或日期的起始。

星期幾」(weekday)修飾詞會將日期往前推移(如果需要)到下一個星期幾編號為 N 的日期。星期日為 0,星期一為 1,依此類推。如果日期已經是所需的星期幾,則「星期幾」修飾詞不會更改日期。

unixepoch」修飾詞(20)僅在緊接在 DDDDDDDDDD 格式的時間值之後才有效。此修飾詞會使 DDDDDDDDDD 不像通常那樣被解釋為儒略日數,而是被解釋為Unix 時間——自 1970 年以來的秒數。如果「unixepoch」修飾詞後面沒有接表示自 1970 年以來秒數的 DDDDDDDDDD 格式的時間值,或者如果有其他修飾詞將「unixepoch」修飾詞與前面的 DDDDDDDDDD 分隔開來,則其行為未定義。

儒略日」(julianday)修飾詞必須緊接在初始時間值之後,且該時間值必須是 DDDDDDDDD 格式。任何其他使用「儒略日」修飾詞的方式都是錯誤的,並且會導致函式返回 NULL。「儒略日」修飾詞會強制將時間值數字解釋為儒略日數。由於這是預設行為,「儒略日」修飾詞幾乎等同於無作用。唯一的區別是,加上「儒略日」會強制使用 DDDDDDDDD 時間值格式,如果使用任何其他時間值格式,則會導致返回 NULL。

自動」(auto)修飾詞必須緊接在初始時間值之後。如果時間值是數值(DDDDDDDDD 格式),則「自動」修飾詞會根據其大小將時間值解釋為儒略日數或 Unix 時間戳記。如果值介於 0.0 和 5373484.499999 之間,則會將其解釋為儒略日數(對應於 -4713-11-24 12:00:00 到 9999-12-31 23:59:59 之間的日期,含)。對於超出有效儒略日數範圍,但介於 -210866760000 到 253402300799 之間的數值,「自動」修飾詞會將該值解釋為 Unix 時間戳記。其他數值超出範圍,並會導致返回 NULL。對於 ISO 8601 文字時間值,「自動」修飾詞無作用。「自動」修飾詞的設計目的是即使在不知道資料庫檔案中儲存的時間值格式,或者在同一欄位在不同列上儲存不同格式時間值的情況下,也能處理時間值。 「自動」修飾詞會自動選擇適當的格式。然而,存在一些歧義。1970 年前 63 天的 Unix 時間戳記將被解釋為儒略日數。當資料集保證不包含該範圍內的日期時,「自動」修飾詞非常有用,但對於可能使用 1970 年最初幾個月的日期的應用程式,則應避免使用。

localtime」修飾詞假設其左側的時間值是世界協調時間 (UTC),並調整該時間值使其成為當地時間。如果「localtime」後面的時間不是 UTC,則行為未定義。「utc」修飾詞與「localtime」相反。「utc」假設其左側的時間值是當地時區,並將該時間值調整為 UTC。如果左側的時間不是當地時間,則「utc」的結果未定義。

subsecond」修飾詞(可縮寫為「subsec」)會提高 datetime()time()unixepoch() 的輸出解析度,以及 strftime() 中「%s」格式字串的解析度。「subsecond」修飾詞對其他日期/時間函數沒有影響。目前的實作將解析度從秒提高到毫秒,但在未來版本的 SQLite 中可能會提高到更高的解析度。當「subsec」與 datetime()time() 一起使用時,結尾的秒數欄位後面會接著一個小數點和一個或多個數字,以顯示小數秒。當「subsec」與 unixepoch() 一起使用時,結果是一個浮點值,表示自 1970-01-01 以來的秒數和小數秒數。「subsecond」和「subsec」修飾詞具有特殊屬性,它們可以作為日期/時間函數的第一個參數(或作為 strftime() 格式字串後的第一個參數)。發生這種情況時,通常在第一個參數中的時間值會被理解為「現在」。例如,要以毫秒精度取得目前時間(以自 1970 年以來的秒數表示)的捷徑是:

SELECT unixepoch('subsec');

4. 範例

計算目前的日期。

SELECT date();

計算目前月份的最後一天。

SELECT date('now','start of month','+1 month','-1 day');

計算給定 Unix 時間戳記 1092941466 的日期和時間。

SELECT datetime(1092941466, 'unixepoch');
SELECT datetime(1092941466, 'auto'); -- 對於 1970 年早期不適用!

計算給定 Unix 時間戳記 1092941466 的日期和時間,並根據您的當地時區進行調整。

SELECT datetime(1092941466, 'unixepoch', 'localtime');

計算目前的 Unix 時間戳記。

SELECT unixepoch();
SELECT strftime('%s');

計算自美國《獨立宣言》簽署以來的天數。

SELECT julianday('now') - julianday('1776-07-04');

計算自 2004 年特定時刻以來的秒數

SELECT unixepoch() - unixepoch('2004-01-01 02:34:56');

計算今年十月第一個星期二的日期。

SELECT date('now','start of year','+9 months','weekday 2');

計算自 Unix 紀元以來的時間(以秒為單位,精確到毫秒)

SELECT (julianday('now') - 2440587.5)*86400.0;
SELECT unixepoch('now','subsec');

計算如果亞伯拉罕·林肯還活著,他今天的年齡

SELECT timediff('now','1809-02-12');

5. 注意事項和錯誤

當地時間的計算很大程度上取決於政治家的想法,因此很難針對所有地區都正確計算。在此實作中,標準 C 函式庫函數 localtime_r() 用於協助計算當地時間。localtime_r() C 函數通常僅適用於 1970 年到 2037 年之間的年份。對於此範圍之外的日期,SQLite 會嘗試將年份映射到此範圍內的等效年份,進行計算,然後將年份映射回原來的年份。

這些函數僅適用於 0000-01-01 00:00:00 到 9999-12-31 23:59:59 之間的日期(儒略日數 1721059.5 到 5373484.5)。對於超出此範圍的日期,這些函數的結果未定義。

非 Vista 版本的 Windows 平台僅支援一套日光節約時間 (DST) 規則。Vista 僅支援兩套。因此,在這些平台上,歷史 DST 的計算將會不正確。例如,在美國,2007 年 DST 規則有所變更。非 Vista 版本的 Windows 平台會將新的 2007 年 DST 規則套用至所有之前的年份。Vista 的處理方式較佳,能正確計算回溯至 1986 年(當時規則也有變更)的結果。

所有內部計算均採用格里曆 (公曆)系統。它們也假設每天的長度正好是 86400 秒;不包含閏秒。

本頁面最後修改時間:2024 年 8 月 14 日 17:04:32 UTC