一、概述
SQLite 支持以下六种日期和时间函数:
- date(time-value, modifier, modifier, ...)
- time(time-value, modifier, modifier, ...)
- datetime(time-value, modifier, modifier, ...)
- julianday(time-value, modifier, modifier, ...)
- unixepoch(time-value, modifier, modifier, ...)
- strftime(format, time-value, modifier, modifier, ...)
所有六个日期和时间函数都采用可选的时间值作为参数,后跟零个或多个修饰符。strftime() 函数还将格式字符串作为其第一个参数。
日期和时间值可以存储为
所有日期时间函数都以上述任何时间格式访问时间值。
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 的情况下它可以是一个整数或浮点数。
- YYYY-MM-DD
- YYYY-MM-DD HH:MM
- YYYY-MM-DD HH:MM:SS
- YYYY-MM-DD HH:MM:SS.SSS
- YYYY-MM-DDTHH:MM
- YYYY-MM-DDTHH:MM:SS
- YYYY-MM-DDTHH:MM:SS.SSS
- HH:MM
- HH:MM:SS
- HH:MM:SS.SSS
- now
- 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.修饰符
时间值后面可以跟零个或多个更改日期和/或时间的修饰符。每个修饰符都是一个应用于其左侧时间值的转换。修饰符从左到右应用;顺序很重要。可用的修饰符如下。
- NNN days
- NNN hours
- NNN minutes
- NNN.NNNN seconds
- NNN months
- NNN years
- start of month
- start of year
- start of day
- weekday N
- unixepoch
- julianday
- auto
- localtime
- 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 秒;没有闰秒。