PostgreSQL 支持 SQL 中所有的日期和时间类型。 在 Table 8-9 中显示。
Table 8-9. 日期/时间类型
名字 | 存储空间 | 描述 | 最低值 | 最高值 | 分辨率 |
---|---|---|---|---|---|
timestamp [ (p) ] [without time zone] | 8 字节 | 包括日期和时间 | 4713 BC | AD 5874897 | 1 毫秒 / 14 位 |
timestamp [ (p) ] with time zone | 8 字节 | 日期和时间,带时区 | 4713 BC | AD 5874897 | 1 毫秒 / 14 位 |
interval [ (p) ] | 12 字节 | 时间间隔 | -178000000 年 | 178000000 年 | 1 毫秒 |
date | 4 字节 | 只用于日期 | 4713 BC | 32767 AD | 1 天 |
time [ (p) ] [ without time zone ] | 8 字节 | 只用于一日内时间 | 00:00:00.00 | 23:59:59.99 | 1 毫秒 |
time [ (p) ] with time zone | 只用于一日内时间,带时区 | 12 字节 | 00:00:00.00+12 | 23:59:59.99-12 | 1 毫秒 |
time ,timestamp 和interval 接受一个可选的 精度值 p,这个精度值声明在秒域后面 小数点之后保留的位数.缺省的时候在精度上是没有明确的绑定的, p 有用的范围对 timestamp和 interval 是从 0 到大约 6。
注意: 如果 timestamp 数值是以双精度浮点数(目前的缺省)的方式存储的, 那么精度的有效限制会小于 6。 timestamp 值是以自 2000-01-01 以来的 秒数存储的,而微秒的精度是为那些在 2000-01-01 前后几年的日期实现的, 对于那些远一些的日子,精度会下降。如果 timestamp 以八字节整数存储 (一个编译时的选项),那么微秒的精度就可以在数值的全部范围内都可以获得。 不过,八位整数的时间戳的日期范围缩小到 4713 BC 到 294276 AD。
注意: 在 PostgreSQL 7.3 以前,只写 timestamp 等效于 timestamp with time zone。 这样是为了和 SQL 兼容。
对于 time 类型,如果使用了八字节的整数存储,那么 p 允许的范围是从 0 到 6,如果使用的是 浮点数存储,那么这个范围是 0 到 10。
类型time with time zone是 SQL 标准定义的, 但是但是整个定义有些方面会导致有问题的用法。在大多数情况下, date,time,timestamp without time zone 和 timestamp with time zone 的组合就应该能提供提供 任何应用需要的日期/时间的完整功能。
类型 abstime 和 reltime 是低分辨率类型,它们被用于系统内部。 我们不鼓励你在新的应用里面使用这些类型,同时我 们支持合适的时候把旧应用中对应的类型转换成目前上面指明的。 因为这些旧类型的部分或全部可能会在未来的版本里消失。
日期和时间的输入几乎可以是任何合理的格式,包括 ISO 8601,SQL-兼容的, 传统 POSTGRES 的和其他的形式。 对于一些格式,日期输入里的月份和日子输入可能会让人模糊, 因此系统支持声明自己预期的这些字段的顺序. 把 datestyle 参数设置为 MDY, 就是“月-日-年”的解析,设置为 DMY 就是 “日-月-年”,而 YMD 是 “年-月-日”。
PostgreSQL 在处理日期/时间输入上比 SQL 标准要求的更灵活. 参阅 Appendix B 获取关于日期/时间输入的准确的分析规则和可识别文本字段, 包括月份,星期几,和时区.
请记住任何日期或者时间的文本输入需要由单引号包围, 就象一个文本字符串一样。 参考 Section 4.1.2.4 获取更多信息.SQL 要求下面的语法
type [ (p) ] 'value'
在这里可选的精度声明中的 p 是一个整数, 对应在秒域中小数部分的位数, 我们可以对 time, timestamp,和 interval 类型声明精度. 允许的精度在上面已经说明。如果在常量声明中没有声明精度, 缺省是文本值的精度。
Table 8-10 显示了 date 类型可能的输入方式。
Table 8-10. 日期输入
例子 | 描述 |
---|---|
January 8, 1999 | 在任何datestyle输入模式下都无歧义 |
1999-01-08 | ISO-8601 格式,任何方式下都是199年1月8号,(建议格式) |
1/8/1999 | 歧义,在MDY下是一月八号;在 DMY 模式下读做八月一日 |
1/18/1999 | 在MDY模式下读做一月十八日,其它模式下被拒绝 |
01/02/03 | MDY 模式下的2003年一月2日; DMY 模式下的 2003 年 2月 1日; YMD 模式下的2001年二月三日; |
1999-Jan-08 | 任何模式下都是一月8日 |
Jan-08-1999 | 任何模式下都是一月8日 |
08-Jan-1999 | 任何模式下都是一月8日 |
99-Jan-08 | 在 YMD 模式下是一月8日,否则错误 |
08-Jan-99 | 一月八日,除了在 YMD 模式下是错误的之外 |
Jan-08-99 | 一月八日,除了在 YMD 模式下是错误的之外 |
19990108 | ISO-8601; 任何模式下都是1999年1月8日 |
990108 | ISO-8601; 任何模式下都是1999年1月8日 |
1999.008 | 年和年里的第几天 |
J2451187 | 儒略日 |
January 8, 99 BC | 公元前99年 |
当日时间类型是 time [ (p) ] without time zone 和 time [ (p) ] with time zone。 只写 time 等效于 time without time zone。
这些类型的有效输入由当日时间后面跟着可选的时区组成。 (参阅 Table 8-11。) 如果在 time without time zone 类型的输入 中声明了时区,那么它会被无声地忽略。
时间戳 类型的有效输入由一个 日期和时间的联接组成,后面跟着一个可选的 AD 或者 BC,然后再跟着可选的时区.(见Table 8-12.) 因此
1999-01-08 04:05:06
和
1999-01-08 04:05:06 -8:00
是一个有效的数值, 它是兼容 ISO 8601 的.另外,下面这种使用广泛的格式
January 8 04:05:06 1999 PST
也受支持.
对于 timestamp [without time zone],任何在输入中 声明的时区都被悄悄吞掉.也就是说,生成的日期/时间数值是从 输入中明确的日期/时间字段中得出的,并且没有根据时区调整.
对于 timestamp with time zone,内部存储的数值总是 UTC (全球统一时间,以前也叫格林威治时间GMT)。如果 一个输入值有明确的时区声明,那么它将用该时区合适 的偏移量转换成 UTC。如果在输入字串里没有时区声明,那么它就假设是 在系统的 timezone 参数里的那个时区,然后使用这个 timezone 时区转换成 UTC。
如果输出一个 timestamp with time zone,那么它总是从 UTC 转换成当前的 timezone 时区,并且显示为改时区的本地时间。 要看其它时区的该时间,要么修改 timezone,要么使用 AT TIME ZONE 构造(参阅 Section 9.8.3)。
在 timestamp without time zone 和 timestamp with time zone 之间的转换通常假设 timestamp without time zone 数值应该以 timezone 本地时间的形式接受或者写出。 其它得时区引用可以用 AT TIME ZONE 的方式为转换声明。
interval数值可以用下面语法声明:
[@] quantity unit [quantity unit...] [direction]
这里:quantity 是一个数字(可能有符号); unit 是 second, minute, hour, day, week, month, year, decade, century, millennium, 或者这些单位的缩写或复数; direction 可以是 ago 或者为空。符号 @ 是一个可选的杂音.不同的单位以及相应 正确的符号都是隐含地增加的.
日期,小时,分钟,以及秒钟的数量可以在无明确单位标记的情况下声明. 比如,'1 12:59:10' 和 '1 day 12 hours 59 min 10 sec' 读数一样.
可选的精度 p 应该介于 0 和 6 之间, 并且缺省是输入文本的精度.
下面的 SQL-兼容的函数可以用于 对应的数据类型的日期或时间输入: CURRENT_DATE, CURRENT_TIME,CURRENT_TIMESTAMP, LOCALTIME,LOCALTIMESTAMP 后面四个接受一个可选的精度声明. (又见 Section 9.8.4。)
PostgreSQL 为方便起见同样还支持几个特殊输入值, 如在 Table 8-13 里面显示的那样。 值infinity 和 -infinity 是特别在系统内部表示的,并且将按照同样的方式显示; 但是其它的都只是符号缩写,在读取的时候将呗转换成普通的日期/时间值。 所有这些值都被当作普通常量对待,所以需要写在单引号里面。
使用 SET DateStyle,时间/日期类型的输出格式可以设成四种风格之一: ISO 8601,SQL (Ingres),传统的 POSTGRES,和 German 。缺省是 ISO 格式。 (SQL 标准要求使用 ISO 8601 格式。"SQL" 输出格式的名字是历史偶然。)Table 8-14 显示了每种输出风格的例子。date 和 time 类型的 输出当然只是给出的例子里面的日期和时间部分。
Table 8-14. 日期/时间输出风格
风格描述 | 描述 | 例子 |
---|---|---|
ISO | ISO-8601/SQL 标准 | 1997-12-17 07:37:16-08 |
SQL | 传统风格 | 12/17/1997 07:37:16.00 PST |
POSTGRES | 原始风格 | Wed Dec 17 07:37:16 1997 PST |
German | 地区风格 | 17.12.1997 07:37:16.00 PST |
如果声明了 DMY 字段,那么哉 SQL 和 POSTGRES 风格里,日期在月份之前出现,否则月份出现在日期之前。 (参阅 Section 8.5.1 分,看看这个设置是如何影响对输入值的解释。) Table 8-15 显示了一个例子。
Table 8-15. 日期顺序习惯
风格描述 | 描述 | 例子 |
---|---|---|
SQL, DMY | 日/月/年 | 17/12/1997 15:37:16.00 CET |
SQL, MDY | 月/日/年 | 12/17/1997 07:37:16.00 PST |
Postgres, DMY | day/month/year | Wed 17 Dec 07:37:16 1997 PST |
interval 的输出看起来象输入格式,只是象 century 和 week 这样的单位被转换成年和日,而 ago 被转换成合适的符号。在 ISO 模式下输出看起来象
[ quantity unit [ ... ] ] [ days ] [ hours:minutes:sekunden ]
日期/时间风格可以由用户用 SET datestyle 命令 选取,或者在 postgresql.conf 配置文件里的参数 datestyle 设置,或者服务器或客户端的 PGDATESTYLE 环境变量里设置。我们也可以用格式化函数 to_char(参阅 Section 9.7) 来更灵活地控制时间/日期地输出。
时区和时区习惯不仅仅受地球几何形状的影响,还受到政治决定的影响。 到了19世纪,全球的时区变得稍微标准化了些,但是还是易于遭受随意的修改。 PostgreSQL 使用你的 操作系统下层的特性提供时区支持, 这些系统通常只包含 1902 年到 2038 年之间的信息(对应于传统 Unix 系统时间的完整跨度)。 timestamp with time zone 和 time with time zone 将只在这个年代范围内使用时区信息, 如果时间超过这个范围,那么假设时间是 UTC。 但是因为时区支持是来自下层操作系统的时区功能,所以,它可以处理夏时制和其它特殊的行为。
PostgreSQL 在典型应用中尽可能与 SQL 的定义相兼容.但 SQL 标准在日期和时间类型 和功能上有一些奇怪的混淆.两个显而易见的问题是:
date (日期)类型与时区没有联系,而 time (时间)类型却有或可以有. 然而,现实世界的时区只有在与时间和日期都关联时才有意义, 因为时间偏移量(时差)可能因为实行类似夏 时制这样的制度而在一年里有所变化.
缺省的时区用一个数字常量表示与UTC的偏移(时差). 如果这样, 当跨 DST 界限做日期/时间算术时, 我们根本不可能把夏时制这样的因素计算进去.
为了克服这些困难,我们建议在使用时区的时候, 使用那些同时包含日期和时间的日期/时间类型. 我们建议不要使用类型 time with time zone (尽管 PostgreSQL 出于合理应用以及为了与其他RDBMS实现兼容的考虑支持这个类型). PostgreSQL 假设你用于任何类型的本地时区 都只包含日期或时间.
在系统内部,所有日期和时间都是用全球统一时间UTC格式存储, 时间在发给客户前端前由数据库服务器转换成本地时间, 因而缺省的时区是服务器的时区.
有好几种选取服务器使用的时区的方法:
如果没有声明其他的, 直接在服务器主机上的TZ环境变量作为服务器的缺省时区.
我们可以在 postgresql.conf 文件里设置 timezone 配置参数。
如果在客户端设置了PGTZ环境变量,那么libpq在联接时将使用 这个环境变量给后端发送一个 SET TIME ZONE 命令.
SQL 命令 SET TIME ZONE 可以给会话设置时区.
注意: 如果使用了非法的时区,时区变为 UTC(在大多数系统上)。
请参考 Appendix B 获取一个可用 时区的列表。
PostgreSQL 使用儒略历法用于所有日期/时间计算。 如果假设一年的长度是365.2425天时,这个方法可以 很精确地预计/计算从4713 BC(公元前4713年)到很久的未来的任意一天的日期。
19世纪以前的日期传统(历法)对一些趣味读物有意义, 但是在我们这里好象没有充分的理由把它们编码入日 期/时间控制器里面去。