PostgreSQL 使用一个内部的启发式分析器 用于所有的日期/时间支持.日期和时间都是以字串形式输入的, 然后用一个初步的判断分解为在该数域里可以有什么样的信息. 每个数域都被解释,并且要么是被赋予一个数字值,要么是忽略, 要么是被拒绝.分析器里包含内部的查询表,用于所有文本域, 包括月份,星期几,和时区.
这份附录包含这些查询表的信息,以及描述了分析器用来对时间和日期 解码的步骤.
A.1. 日期/时间输入解析
日期/时间类型都是使用一套通用的过程进行解析的。
日期/时间输入解析
1.
把输入字串分解为一个个记号,然后把每个记号分成字串, 时间,时区,或者数字几类。
1.
如果一个数字记号包含一个冒号(:), 那么这是一个时间字串。包括随后所有的数据位和冒号。
2.
如果这个数字记号包含一个划线(-),斜杠(/), 或者两个或多个点(.),那么它就是一个日期字串, 可能有一个文本月份。
3.
如果这个记号只是数字,那么它要么是一个单独的字段, 要么是一个 ISO 8601 连接的日期(比如,19990113 是 1999 年一月 13 日)或者是连接的时间(比如,141516 是 14:15:16)。
4.
如果记号以一个加号(+)开头或者减号(-)开头, 那么它要么是一个时区,要么就是一个特殊的字段。
2.
如果记号是一个文本字串,那么和可能的字串进行匹配。
1.
做一次二分表查找,看看这个记号是特殊字串(比如,today), 日期(比如,Thursday),月份(比如,January), 还是一个无关痛痒的字(比如,at,on)。
为字段设置数值和位掩码。 比如,为 today 设置年,月,日, 以及为 now 这样的还需要设置另外的时,分,秒。
2.
如果没有找到,则做一次类似的二分表搜索,找与记号匹配的时区。
3.
如果还没有找到,抛出一个错误。
3.
记号是一个数字或者数字字段。
1.
如果超过4位数字,而且前面也没有读到其它日期字段, 那么就解释成一个"连接的日期"(比如,19990118)。 8和6位分别解释成年,月,和日,而7和5位分别解释成年,年日。
2.
如果记号是三位数字,并且已经解码了一个年份,那么解释成年日。
3.
如果已经读取了四和六位数字,并且已经读取了一个年份, 那么就解释成时间。
4.
如果是四或更多位,则解析成一个年份。
5.
如果是欧洲日期模式,并且还未读取到日期字段,并且数值小于或等于31, 那么解析成某一天。
6.
如果还未读取月份字段,并且数值小于或等于12,那么解析成月份。
7.
如果日期域尚未读取,并且数值小于或等于31,则解析成一天。
8.
如果是两位或者四或更多位数字,那么解析成一年。
9.
否则,抛出一个错误。
4.
如果声明了 BC,则对年份取其负数并加一,用于内部保存。 (在格里高利历法里没有零年,所以数字上的 1BC 是公元零年。)
5.
如果没有声明 BC,并且年份字段有两个数据位的长度, 那么把年份调整为 4 位。如果该字段小于 70,那么加 2000;否则,加 1900。
技巧: 格里高利年份 AD 1-99可以用前导零的方式使用4位数字 (也就是说,0099 是 AD 99)。以前的 PostgreSQL 版本接受三位数字的年份和一位数字的年份,但是从版本 7.0 开始,这个 规则更严格了,以减少可能的混淆。
Table A-1 显示了可以用作月份的名字 缩写的记号。
Table A-1. 月份缩写
月份缩写
AprilApr
AugustAug
DecemberDec
FebruaryFeb
JanuaryJan
JulyJul
JuneJun
MarchMar
NovemberNov
OctoberOct
SeptemberSep, Sept
注意: 三月没有明确的缩写,原因显而易见.
Table A-2 显示了允许用作星期几的名字。
Table A-2. 星期几的缩写
日子缩写
SundaySun
MondayMon
TuesdayTue, Tues
WednesdayWed, Weds
ThursdayThu, Thur, Thurs
FridayFri
SaturdaySat
Table A-3 显示了用于各种修饰 用途的记号。
Table A-3. 日期/时间字段修饰词
标识符描述
ABSTIME忽略的关键字
AM12:00 之前的时间
AT忽略的关键字
JULIAN, JD, J下一字段是 Julian 日期
ON忽略的关键字
PM12:00 或 12:00 之后的时间
T下一个字段是时间
关键字 ABSTIME 被忽略是由于历史原因; 在非常老的 PostgreSQL 版本里, 类型为 ABSTIME 非法的字段会被当做 Invalid Abstime 发出.不过现在不再是这样了, 并且这个关键字可能在未来版本中被删除.
Table A-4 显示了 PostgreSQL 可以识别的时区缩写。 PostgreSQL 包含一个内部的小表用以时区解码。 因为目前还没有标准的操作系统接口可以用于访问通用的跨时区的时区信息。 不过,下层的 OS 的确提供了输出 时区信息。
这个表是以它们相对 UTC 的时区偏移量来组织的,而不是按照字母顺序; 我们的目的是能实现匹配那些区域中有这些缩写的区域用户, 以免这些缩写混淆.
Table A-4. 时区缩写
时区与 UTC 的偏移量描述
NZDT+13:00新西兰白昼时间
IDLE+12:00国际日期变更线,东边
NZST+12:00新西兰标准时间
NZT+12:00新西兰时间
AESST+11:00澳大利亚东部标准夏时制
ACSST+10:30中澳大利亚标准夏时制
CADT+10:30中澳大利亚夏时制
SADT+10:30南澳大利亚夏时制
AEST+10:00澳大利亚东部标准时间
EAST+10:00东澳大利亚标准时间
GST+10:00关岛标准时间,USSR Zone 9
LIGT+10:00澳大利亚墨尔本
CAST+09:30中澳大利亚标准时间
SAST+09:30南澳大利亚标准时间
CAST+09:30中澳大利亚标准时间
AWSST+09:00澳大利亚西部标准夏时制
JST+09:00日本标准时间,(USSR Zone 8)
KST+09:00韩国标准时间
MHT+09:00Kwajalein Time
WDT+09:00西澳大利亚夏时制
MT+08:30毛里求斯(moluccas)时间(?)
AWST+08:00 澳大利亚西部标准时间
CCT+08:00 中国沿海时间
WADT+08:00西澳大利亚夏时制
WST+08:00西澳大利亚标准时间
JT+07:30爪哇时间
ALMST+07:00Almaty 夏令时
WAST+07:00西澳大利亚标准时间
CXT+07:00Christmas (复活节?)岛时间
MMT+06:30Myannar 时间
ALMT+06:00Almaty 时间
MAWT+06:00Mawson (Antarctica) Time
IOT+05:00印度 Chagos 时间
MVT+05:00Maldives (?)岛时间
TFT+05:00Kerguelen 时间
AFT+04:30阿富汗时间
EAST+04:00Antananarivo Savings Time
MUT+04:00Mauritius Island Time
RET+04:00Reunion Island Time
SCT+04:00Mahe Island Time
IRT, IT+03:30伊朗时间
EAT+03:00Antananarivo, Comoro Time
BT+03:00 巴格达时间
EETDST+03:00 东欧夏时制
HMT+03:00Hellas Mediterranean Time (?)
BDST+02:00 British Double Standard Time
CEST+02:00 Central European Savings Time
CETDST+02:00 中欧夏时制
EET+02:00 东欧,(USSR Zone 1)
FWT+02:00法国冬时制
IST+02:00以色列标准时间
MEST+02:00中欧夏时制
METDST+02:00中欧白昼时间
SST+02:00瑞典夏时制
BST+01:00 英国夏时制
CET+01:00 中欧时间
DNT+01:00 Dansk Normal Tid
FST+01:00 法国夏时制
MET+01:00中欧时间
MEWT+01:00中欧冬时制
MEZ+01:00中欧时区
NOR+01:00挪威标准时间
SET+01:00Seychelles Time(?)
SWT+01:00瑞典冬时制
WETDST+01:00西欧光照利用时间(夏时制)
GMT0:00格林威治标准时间
UT+00:00全球时间
UTC+00:00校准的全球时间
Z+00:00和 UTC 相同
ZULU+00:00和 UTC 相同
WET+00:00西欧
WAT-01:00西非时间
NDT-02:30纽芬兰(Newfoundland)白昼时间
ADT-03:00 大西洋白昼时间
AWT-03:00(未知)
NFT-03:30纽芬兰(Newfoundland)标准时间
NST-03:30纽芬兰(Newfoundland)标准时间
AST-04:00 大西洋标准时间(加拿大)
ACST-04:00Atlantic/Porto Acre 夏令时
ACT-05:00Atlantic/Porto Acre 标准时间
EDT-04:00 东部白昼时间
CDT-05:00 中部白昼时间
EST-05:00 东部标准时间
CST-06:00 中部标准时间
MDT-06:00山区白昼时间(译注:Mountain Daylight Time那位知道怎么译?)
MST-07:00山区标准时间
PDT-07:00太平洋白昼时间
AKDT-08:00阿拉斯加白昼时间
PST-08:00太平洋标准时间
YDT-08:00Yukon 白昼时间
AKST-09:00阿拉斯加标准时间
HDT-09:00夏威仪/阿拉斯加白昼时间
YST-09:00Yukon 标准时
MART-09:30马克萨司群岛时间
AHST-10:00夏威夷-阿拉斯加标准时间
HST-10:00夏威夷标准时间
CAT-10:00中阿拉斯加时间
NT-11:00州时间(Nome Time)
IDLW-12:00国际日期变更线,西边
澳大利亚时区. 澳大利亚时区名和南北美常用的时区名之间有三个冲突: ACST,CST,和 EST。 设置了运行时选项USE_AUSTRALIAN_RULES,那么 CST ,EST 和 SAT 将被解释为澳大利亚时区的名字。 如 Table A-5 所示。 如果它为假(缺省),CST 和 EST 将 被解释成美国时区名字,而SAT 则是 表示"Saturday(星期六)"的无用字符.
Table A-5. 澳大利亚时区缩写
时区与 UTC 的偏移量描述
ACST+09:30中澳大利亚标准时间
CST+10:30澳大利亚中部标准时间
EST+10:00澳大利亚东部标准时间
SAT+09:30南澳大利亚标准时间
儒略历是由法国学者 Joseph Justus Scaliger (1540-1609)发明的, 名称可能是取自 Scaliger 的父亲, 意大利学者Julius Caesar Scaliger (1484-1558)。 天文学家已经用儒略周期为自 4713 BC 一月一日以来的每一天赋予了一个唯一的数字。 这就是所谓的儒略历(JD)。 JD 0 指定为 4713 BC 一月一日正午 UTC 到 4713 BC 一月二日正午 UTC 的 24 小时。
"儒略日(julian Day)" 与“儒略历(Julian Date)”不同。 儒略历是 Julius Caesar 在 45 BC 发明的。一直用到大约 1582 年, 这时各国开始使用罗马历法。在儒略历里面, 一年是近似 365 1/4 天 = 365.25 天。 这样大约每 128 年就有一天的误差。
不断积累的历法错误促使教皇格里高利十三世(Gregory XIII)按照与弥撒议会 ( Council of Trent)一致的精神改革了历法。 在罗马历法里,一年是近似 365 + 97 / 400 天 = 365.2425 天。 因此对应于罗马历法,大约要 3300 年,才会积累一天的误差。
近似的 365+97/400 是通过利用下面的规则, 规定每 400 年有 97 个闰年实现的:
每个可被 4 整除的年是一个闰年。
不过,可被 100 整除的年不是闰年。
但是,可以被 400 整除的年还是闰年。
因此,1700,1800,1900,2100 和 2200 年都不是闰年。而1600,2000,和 2400年是闰年。 相比而言,旧式的 Julian 历法里面只有能被 4 整除的年是闰年。
1582 二月,罗马教廷要求从 1582 年十月减去十天, 因此1852 年十月四日后面紧跟着就是十五日。 在意大利,波兰,葡萄牙 和西班牙都这样处理了。 其他天主教国家也很快跟着这么做了,但是新教国家不愿意修改, 而且希腊等东正教国家直到20世纪初才修改。 这个改革在英国及其殖民地(包括现在的 USA)在 1752年执行了。 这样 1752 年九月二日后面跟着 1752 年九月十四日。 这就是为什么 Unix 系统的cal生成下面的输出:
$ cal 9 1752
September 1752
S M Tu W Th F S
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
注意: SQL 标准声称 "在日期时间字面'datetime literal'的定义上, '日期时间(datetime)值' 中的日期和时间根据罗马历法受自然法则的约束 "。 在 1752-09-03 和 1752-09-13 之间的日子, 尽管被罗马教廷的教令取消了,但为了和 "自然法则"相一致,因而是有效的日期。
在世界的不同的地方,发明了许多不同的历法,有许多比罗马历法系统还早。 例如,中国历法的最早应用可以追溯到公元前14世纪。 传说黄帝在 2637 BC 就发明了这个历法。 中华人民共和国使用罗马历法用于民用。中国历法用于决定节日/节气。