pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
PostgreSQL 支持全套 SQL 日期和时间类型,如 表 8.9 所示。
表 8.9. 日期/时间类型
| 名字 | 存储尺寸 | 描述 | 低值 | 高值 | 精度 |
|---|---|---|---|---|---|
timestamp [ ( |
8字节 | 日期和时间 | 4713 BC | 5874897 AD | 1微秒 / 14位 |
timestamp [ ( |
8字节 | 包括日期和时间,有时区 | 4713 BC | 5874897 AD | 1微秒 / 14位 |
interval [ ( |
12字节 | 时间间隔 | -178000000年 | 178000000年 | 1微秒 |
date |
4字节 | 仅日期 | 4713 BC | 32767 AD | 1日 |
time [ ( |
8字节 | 仅一天中的时间 | 00:00:00.00 | 23:59:59.99 | 1微秒 |
time [ ( |
12字节 | 仅一天中的时间,带时区 | 00:00:00.00+12 | 23:59:59.99-12 | 1微秒 |
在 PostgreSQL 7.3 之前的版本中,仅写timestamp等效于timestamp with time zone。为了符合 SQL 标准,这一行为已被改变。
time、timestamp 和 interval 都接受一个可选精度值 p,用来指定在秒字段中 保留多少位小数。默认情况下,对精度没有显式上界。 对于 timestamp 和 interval 类型, p 的允许范围是 0 到 6。
当 timestamp 值以双精度浮点数存储(目前的默认方式)时,精度的有效上限可能小于 6。timestamp 值存储为相对 2000-01-01 午夜之前或之后的秒数。对 2000-01-01 前后几年的日期可以达到微秒精度,但对更远的 日期,精度会进一步降低。当 timestamp 值以八字节整数存储(一种编译期选项)时,全部取值范围内都有微秒精度。但八字节整数时间戳的日期范围比上表所示的更有限:从公元前 4713 年到公元 294276 年。
对于 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 标准要求的更灵活。有关日期/时间输入的 精确解析规则,以及可识别的文本字段(包括月份、星期几和时区), 请参见 附录 B。
请记住,任何日期或时间字面值输入都必须像文本字符串一样用单引号 括起来。更多信息请参见 第 4.1.2.4 节。 SQL 要求使用下列语法:
type[ (p) ] 'value'
其中 p 是可选的精度说明,给出秒字段中 保留的小数位数。精度可用于 time、 timestamp 和 interval 类型, 允许的取值范围见上文。如果在常量声明中没有指定 精度,则默认采用该字面值本身的精度。
表 8.10显示了date类型可能的输入方式。
表 8.10. 日期输入
| 示例 | 描述 |
|---|---|
| January 8, 1999 | 在任何datestyle输入模式下都无歧义 |
| 1999-01-08 | ISO 8601;任何模式下的1月8日 (推荐格式) |
| 1/8/1999 | MDY模式中的1月8日;DMY模式中的8月1日 |
| 1/18/1999 | MDY模式中的1月18日;在其他模式中被拒绝 |
| 01/02/03 | MDY模式中的2003年1月2日; DMY模式中的2003年2月1日; YMD模式中的2001年2月3日 |
| 1999-Jan-08 | 任何模式下的1月8日 |
| Jan-08-1999 | 任何模式下的1月8日 |
| 08-Jan-1999 | 任何模式下的1月8日 |
| 99-Jan-08 | YMD模式中的1月8日,否则错误 |
| 08-Jan-99 | 1月8日,除了在YMD模式中错误 |
| Jan-08-99 | 1月8日,除了在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 zonetime [ (。 单独写 p) ] with time zonetime 等效于 time without time zone。
这些类型的有效输入由一个一天中的时间,加上一个可选时区组成 (见 表 8.11 和 表 8.12)。如果在 time without time zone 的输入中指定了时区,它会被 静默忽略。
表 8.11. 时间输入
| 示例 | 描述 |
|---|---|
04:05:06.789 |
ISO 8601 |
04:05:06 |
ISO 8601 |
04:05 |
ISO 8601 |
040506 |
ISO 8601 |
04:05 AM |
和04:05一样,AM并不影响值 |
04:05 PM |
和16:05一样;输入的小时必须 <= 12 |
04:05:06.789-8 |
ISO 8601 |
04:05:06-08:00 |
ISO 8601 |
04:05-08:00 |
ISO 8601 |
040506-08 |
ISO 8601 |
04:05:06 PST |
名称指定的时区 |
表 8.12. 时区输入
| 示例 | 描述 |
|---|---|
PST |
太平洋标准时间 |
-8:00 |
PST的ISO-8601偏移 |
-800 |
PST的ISO-8601偏移 |
-8 |
PST的ISO-8601偏移 |
zulu |
UTC的军方缩写 |
z |
zulu的缩写形式 |
时间戳类型的有效输入由一个日期和一个时间连接而成,其后可跟可选的 AD 或 BC,再后可跟可选的时区。因此
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(Universal Coordinated Time,传统上称为格林尼治标准时间 GMT)。指定了显式时区的输入值会按该时区的相应偏移转换为 UTC。如果输入串中没有给出时区,则假定它位于系统 timezone 参数指示的时区,并按 timezone 时区的偏移转换为 UTC。
当输出一个 timestamp with time zone 值时,它总会从 UTC 转换到当前 timezone 时区,并显示为该时区的 本地时间。若要查看其他时区的时间,可以修改 timezone,或者使用 AT TIME ZONE 构造(见 第 9.8.3 节)。
在 timestamp without time zone 和 timestamp with time zone 之间转换时,通常假定 timestamp without time zone 值应被解释为,或输出为, timezone 本地时间。要为该转换指定不同的时区, 可以使用 AT TIME ZONE。
interval值可以用下列语法书写:
[@]quantityunit[quantityunit...] [direction]
其中:quantity是一个数字(可带符号); unit是second、 minute、hour、day、 week、month、year、 decade、century、millennium, 或者这些单位的缩写或复数形式; direction可以是ago或为空。 at 符号(@)是可选的噪音。不同单位的数量会带 着适当的符号被隐式地累加起来。
天、小时、分钟和秒的数量可以不带显式的单位标记来指定。 例如,'1 12:59:10'的读法与 '1 day 12 hours 59 min 10 sec'相同。
可选的精度p应当在 0 到 6 之间, 默认为输入字面量的精度。
下面的函数与 SQL 兼容,可用作相应数据类型的日期或时间值: CURRENT_DATE、CURRENT_TIME、 CURRENT_TIMESTAMP、LOCALTIME、 LOCALTIMESTAMP。后四个函数接受可选的精度说明。(另见 第 9.8.4 节。)
PostgreSQL 还为方便使用支持几种 特殊日期/时间输入值,如 表 8.13 所示。值 infinity 和 -infinity 在系统内部有特殊的表示并以相同方式显示;其余的只是记法上的简写,读取时会被转换为普通的日期/时间值。所有这些值都被当作普通常量处理,需要写成单引号括起来的形式。
表 8.13. 特殊日期/时间输入
| 输入字符串 | 有效类型 | 描述 |
|---|---|---|
epoch |
date, timestamp |
1970-01-01 00:00:00+00(Unix系统时间0) |
infinity |
timestamp |
晚于所有其他时间戳 |
-infinity |
timestamp |
早于所有其他时间戳 |
now |
date, time, timestamp |
当前事务的开始时间 |
today |
date, timestamp |
今天午夜 |
tomorrow |
date, timestamp |
明天午夜 |
yesterday |
date, timestamp |
昨天午夜 |
allballs |
time |
00:00:00.00 UTC |
日期/时间类型的输出格式可以设为四种样式之一:ISO 8601、SQL(Ingres)、传统的 POSTGRES 和 German,这通过命令SET datestyle设置。默认是ISO格式。(SQL标准要求使用 ISO 8601 格式。之所以存在名为“SQL”的输出格式,只是历史原因。)表 8.14展示了各种输出样式的示例。date和time类型的输出当然只包含给定示例中相应的日期部分或时间部分。
表 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 |
SQL和POSTGRES风格中,如果指定了 DMY 字段顺序,“日”将出现在“月”之前,否则“月”出现在“日”之前(有关该设置如何影响输入值的解释,请参考第 8.5.1 节)。表 8.15给出了示例。
表 8.15. 日期顺序习惯
datestyle 设置 |
输入顺序 | 输出示例 |
|---|---|---|
SQL, DMY |
day/month/year |
17/12/1997 15:37:16.00 CET |
SQL, MDY |
month/day/year |
12/17/1997 07:37:16.00 PST |
Postgres, DMY |
day/month/year |
Wed 17 Dec 07:37:16 1997 PST |
interval 的输出与输入格式相似,区别在于像 century 或 wek 这样的单位会被转换为年和天,并且 ago 会被转换为适当的符号。在 ISO 模式下输出形如
[quantityunit[ ... ] ] [days] [hours:minutes:sekunden]
用户可以用 SET datestyle 命令、 postgresql.conf 配置文件中的 datestyle 参数,或服务器/客户端上的 PGDATESTYLE 环境变量来选择日期/时间风格。格式化函数 to_char(见 第 9.7 节)也可作为一种更灵活的日期/时间输出格式化手段。
时区及时区惯例受政治决策的影响,而不只是地球几何。世界各地的时区在 20 世纪期间变得多少标准化了一些,但仍容易发生任意的变更。PostgreSQL 使用操作系统的底层特性来提供输出时区支持,而这些系统通常只包含 1902 到 2038 年期间的信息(对应传统 Unix 系统时间的全部范围)。timestamp with time zone 和 time with time zone 只在该年份范围内使用时区信息,并假定范围外的时间位于 UTC。不过由于时区支持源自底层操作系统的时区能力,它可以处理夏令时和其他特殊行为。
PostgreSQL 力求在典型用法上与 SQL 标准定义兼容。但 SQL 标准对日期和 时间类型和能力方面有一种奇怪的组合。两个明显的问题是:
尽管 date 类型没有关联的时区,time 类型却可以有关联的时区。现实世界中的时区若不同时关联日期和时间就可能没有意义,因为偏移量在一年中可能随夏令时边界而变化。
默认时区被指定为相对 UTC 的固定数字偏移。在跨 DST 边界进行日期/时间运算时无法适应夏令时。
为解决这些困难,我们建议在使用时区时选用同时包含日期和时间的日期/时间类型。我们建议不要使用 time with time zone 类型(尽管为了旧应用以及与其他 SQL 实现的兼容,PostgreSQL 支持它)。对于只包含日期或只包含时间的类型,PostgreSQL 假定使用你的本地时区。
所有日期和时间在内部都以 UTC 存储。时间在发送给客户端之前会被转换为数据库服务器上的本地时间,因此默认情况下采用服务器时区。
有几种方法可以选择服务器使用的时区:
如果没有指定其他时区,服务器主机上的 TZ 环境变量将被服务器用作默认时区。
timezone 配置参数可以在文件 postgresql.conf 中设置。
libpq客户端使用PGTZ环境变量在连接时向服务器发送SET TIME ZONE命令。
SQL 命令 SET TIME ZONE 设置会话的时区。
如果指定了无效的时区,时区会变成 UTC(至少在大多数系统上如此)。
有关可用时区的列表,请参见附录 B。
PostgreSQL在所有日期/时间计算中使用儒略日。这带来一个有用的特性:在假定一年长度为 365.2425 天的前提下,能够正确计算从公元前 4713 年到遥远未来的日期。
19 世纪之前的日期约定读起来很有意思,但它们并不足够一致,不值得写进日期/时间处理器中。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。