日期和时间函数

、概述

SQLite 支持以下六种日期和时间函数:

  1. date(time-value, modifier, modifier, ...)
  2. time(time-value, modifier, modifier, ...)
  3. datetime(time-value, modifier, modifier, ...)
  4. julianday(time-value, modifier, modifier, ...)
  5. unixepoch(time-value, modifier, modifier, ...)
  6. strftime(format, time-value, modifier, modifier, ...)

所有六个日期和时间函数都采用可选的时间值作为参数,后跟零个或多个修饰符。strftime() 函数还将格式字符串作为其第一个参数。

日期和时间值可以存储为

  • ISO-8601格式 子集中的文本,
  • 代表儒略日的数字,或
  • 代表自(或之前)1970-01-01 00:00:00 UTC(unix 时间戳)以来的秒数的数字。

所有日期时间函数都以上述任何时间格式访问时间值。

date() 函数以文本格式返回日期:YYYY-MM-DD。

time() 函数以文本格式返回时间:HH:MM:SS。

datetime() 函数以相同格式的文本形式返回日期和时间:YYYY-MM-DD HH:MM:SS。

julianday() 函数返回 儒略日- 自公元前 4714 年 11 月 24 日格林威治中午以来的小数天数(Proleptic Gregorian calendar)。

unixepoch() 函数返回一个 unix 时间戳 - 自 1970-01-01 00:00:00 UTC 以来的秒数。unixepoch() 总是返回一个整数,即使输入的时间值具有毫秒精度。

strftime() 例程返回根据指定为第一个参数的格式字符串格式化的日期。格式字符串支持标准 C 库的strftime() 函数中最常见的替换 以及两个新替换,%f 和 %J。以下是有效 strftime() 替换的完整列表:

%d一个月中的第几天:00
%F小数秒:SS.SSS
%H小时:00-24
%j年份:001-366
%J儒略日数(小数)
%m月份:01-12
%M分钟:00-59
%s自 1970-01-01 以来的秒数
%S秒数:00-59
%w星期 0-6 星期日 == 0
%W一年中的第几周:00-53
%Y年份:0000-9999
%%%

所有其他日期和时间函数都可以用 strftime() 表示:

功能等效(或接近)strftime()
date(...) strftime('%Y-%m-%d', ...)
time(...) strftime('%H:%M:%S', ...)
datetime(...) strftime('%Y-%m-%d %H:%M:%S', ...)
julianday(...) strftime('%J', ...) -- 注 1
unixepoch(...) strftime('%s', ...) -- 注 1

date()、time() 和 datetime() 函数都返回文本,因此它们的 strftime() 等价物是准确的。但是(注 1)julianday() 和 unixepoch() 函数返回数值。它们的 strftime() 等价物返回字符串,即相应数字的文本表示形式。

提供 strftime() 以外的函数的主要原因是为了方便和效率。julianday() 和 unixepoch() 函数分别返回实数和整数值,并且不会因将 '%J' 或 '%s' 格式说明符与 strftime() 函数一起使用而导致格式转换成本或不精确。

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 方法获得的当前日期和时间。对于同一sqlite3_step()调用中的多次调用,日期和时间函数的“现在”参数总是返回完全相同的值使用通用协调时间 (UTC)格式 12 是 儒略日数 表示为整数或浮点值。如果格式 12 紧跟在“auto”或“unixepoch”修饰符之后,它也可能被解释为 unix 时间戳。

格式 2 到 10 可以选择性地后跟“ [+-]HH:MM ”或“ Z ”形式的时区指示符。日期和时间函数在内部使用 UTC 或“zulu”时间,因此“Z”后缀是空操作。从指示的日期和时间中减去任何非零“HH:MM”后缀以计算祖鲁时间。例如,以下所有时间值都是等效的:

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 位有效数字,但日期/时间函数实际上会接受表示 Julian 日数所需的尽可能多或尽可能少的数字。

可以省略时间值(和所有修饰符),在这种情况下假定时间值为“现在”。

3.修饰符

时间值后面可以跟零个或多个更改日期和/或时间的修饰符。每个修饰符都是一个应用于其左侧时间值的转换。修饰符从左到右应用;顺序很重要。可用的修饰符如下。

  1. NNN days
  2. NNN hours
  3. NNN minutes
  4. NNN.NNNN seconds
  5. NNN months
  6. NNN years
  7. start of month
  8. start of year
  9. start of day
  10. weekday N
  11. unixepoch
  12. julianday
  13. auto
  14. localtime
  15. utc

前六个修饰符(1 到 6)只是将指定的时间量添加到左侧参数指定的日期和时间。修饰符名称末尾的“s”字符是可选的。请注意,“±NNN 月”的工作原理是将原始日期呈现为 YYYY-MM-DD 格式,将 ±NNN 添加到 MM 月值,然后对结果进行归一化。因此,例如,由“+1 个月”修改的日期 2001-03-31 最初产生 2001-04-31,但四月只有 30 天,因此日期标准化为 2001-05-01。当原始日期是闰年的 2 月 29 日并且修饰符是 ±N 年(其中 N 不是四的倍数)时,会出现类似的效果。

“开始于”修饰符(7 到 9)将日期向后移动到主题月、年或日的开始。

如果需要,“工作日”修饰符将日期向前推进到工作日编号为 N 的下一个日期。星期日为 0,星期一为 1,依此类推。如果日期已经在所需的工作日,则“工作日”修饰符会使日期保持不变。

“unixepoch”修饰符 (11) 只有紧跟在 DDDDDDDDDD 格式的时间值后才有效。此修饰符导致 DDDDDDDDDD 不像通常那样被解释为儒略日数字,而是解释为 Unix 时间- 自 1970 年以来的秒数。如果“unixepoch”修饰符不遵循 DDDDDDDDDD 形式的时间值,它表示自 1970 年以来的秒数,或者如果其他修饰符将“unixepoch”修饰符与之前的 DDDDDDDDDD 分开,则行为未定义。对于 3.16.0 (2017-01-02) 之前的 SQLite 版本,“unixepoch”修饰符仅适用于 0000-01-01 00:00:00 和 5352-11-01 10:52:47 之间的日期(unix 时间-62167219200 到 106751991167)。

“julianday”修饰符必须紧跟初始时间值,其格式必须为 DDDDDDDDD。“julianday”修饰符的任何其他使用都是错误的,并导致函数返回 NULL。'julianday' 修饰符强制将时间值数字解释为儒略日数字。由于这是默认行为,'julianday' 修饰符只不过是一个空操作。唯一的区别是添加“julianday”会强制采用 DDDDDDDDD 时间值格式,如果使用任何其他时间值格式,则会导致返回 NULL。

“自动”修饰符必须紧跟在初始时间值之后。如果时间值是数字(DDDDDDDDDD 格式),则“auto”修饰符会导致时间值根据其大小被解释为儒略日数字或 unix 时间戳。如果该值介于 0.0 和 5373484.499999 之间,则将其解释为儒略日数(对应于 -4713-11-24 12:00:00 和 9999-12-31 23:59:59 之间的日期,包括在内)。对于超出有效儒略日数字范围但在 -210866760000 到 253402300799 范围内的数值,“auto”修饰符会导致该值被解释为 unix 时间戳。其他数值超出范围并导致 NULL 返回。'auto' 修饰符是文本时间值的空操作。

'auto' 修饰符可用于处理日期/时间值,即使在不知道使用的是儒略日数字还是 unix 时间戳格式的情况下也是如此。'auto' 修饰符将自动选择适当的格式。然而,有一个模糊的区域。1970 年前 63 天的 Unix 时间戳将被解释为儒略日数。当保证数据集不包含该区域内的任何日期时,“auto”修饰符非常有用,但对于可能使用 1970 年初月份日期的应用程序应避免使用。

“本地时间”修饰符 (14) 假定其左侧的时间值采用通用协调时间 (UTC),并调整该时间值以使其采用本地时间。如果“本地时间”遵循的时间不是 UTC,则行为未定义。“utc”修饰符与“localtime”相反。“utc”假定其左侧的时间值处于本地时区,并将该时间值调整为 UTC。如果左边的时间不是本地时间,则“utc”的结果未定义。

4.例子

计算当前日期。

SELECT date();

计算当前月份的最后一天。

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

计算给定 unix 时间戳 1092941466 的日期和时间。

SELECT datetime(1092941466, 'unixepoch');
SELECT datetime(1092941466, 'auto'); -- Does not work for early 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');

计算当年 10 月第一个星期二的日期。

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

计算自 unix 纪元以来的时间,以秒为单位,精度为毫秒:

SELECT (julianday('now') - 2440587.5)*86400.0;

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 计算将不正确。例如,在美国,DST 规则在 2007 年发生了变化。非 Vista Windows 平台也将新的 2007 DST 规则应用于所有以前的年份。Vista 在 1986 年的结果正确方面做得更好,当时规则也发生了变化。

所有内部计算均采用 公历 系统。他们还假设每天的持续时间正好是 86400 秒;没有闰秒。