3.5. 日期/时间类型 #
PostgreSQL 支持全套 SQL 日期和时间类型。
表 3.10. 日期/时间类型
| 类型 | 描述 | 存储尺寸 | 最早 | 最晚 | 精度 |
|---|---|---|---|---|---|
timestamp [ ( | 日期和时间 | 8字节 | 4713 BC | AD 1465001 | 1微秒 / 14位 |
timestamp [ ( | 日期和时间 | 8字节 | 4713 BC | AD 1465001 | 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微秒 |
time、timestamp 和 interval
接受可选的精度值
p,它指定秒字段保留的小数位数。默认情况下精度没有显式上限。精度的有效上限由底层的双精度浮点数决定(interval
以秒计,timestamp
以相对 2000-01-01
的秒数计)。p
的有用范围对
timestamp 是 0 到约
6,对
interval
则可能更大。系统将接受 0 到
13 的
p。
时区及时区惯例受政治决策的影响,而不只是地球几何。世界各地的时区在
20 世纪期间变得多少标准化了一些,但仍容易发生任意的变更。PostgreSQL
使用操作系统的底层特性来提供输出时区支持,而这些系统通常只包含
1902 到 2038 年期间的信息(对应传统
Unix 系统时间的全部范围)。timestamp with time zone 和
time with time
zone 只在该年份范围内使用时区信息,并假定范围外的时间位于
UTC。
为了确保从早于 7.0 的
PostgreSQL 版本升级的路径,我们识别 datetime(等价于 timestamp)和
timespan(等价于 interval)。这些类型现在被限制为只具有到
timestamp 和
interval
的隐式转换,对它们的支持将在
PostgreSQL
的下一个版本(可能名为
7.3)中移除。
abstime
和 reltime
类型是内部使用的低精度类型。不鼓励在新应用中使用这些类型,并建议在合适时把旧的迁移过去。这些内部类型中的任何一种或全部都可能在未来的版本中消失。
3.5.1. 日期/时间输入 #
日期和时间输入几乎可以采用任何合理的格式,包括
ISO 8601、SQL
兼容格式、传统
PostgreSQL 格式等。对于某些格式,日期输入中月和日的顺序可能有歧义,因此支持指定所期望的这些字段的顺序。命令
SET DateStyle TO 'US'
或
SET DateStyle TO 'NonEuropean'
指定“月在前”的变体,命令
SET DateStyle TO 'European'
则设置“日在前”的变体。ISO
风格是默认值,但这一默认可以在编译时或运行时改变。
PostgreSQL 在处理日期/时间方面比 SQL 标准要求的更灵活。关于日期/时间输入的精确解析规则以及可识别的文本字段(包括月份、星期几和时区),参见附录 A。
请记住,任何日期或时间字面值输入都必须像文本字符串一样用单引号括起来。更多信息请参见第 1.1.2.5 节。SQL9x 要求使用下列语法
type[ (p) ] 'value'
其中可选精度说明中的
p
是一个对应于秒字段小数位数的整数。可以为
time、timestamp 和
interval 类型指定精度。
3.5.1.1. date
下面是 date 类型的一些可能输入。
表 3.11. 日期输入
| 示例 | 描述 |
|---|---|
| January 8, 1999 | 无歧义 |
| 1999-01-08 | ISO-8601 格式,推荐 |
| 1/8/1999 | 美式;在欧洲模式下读作 8 月 1 日 |
| 8/1/1999 | 欧式;在美式模式下读作 8 月 1 日 |
| 1/18/1999 | 美式;在任何模式下都读作 1 月 18 日 |
| 19990108 | ISO-8601 年、月、日 |
| 990108 | ISO-8601 年、月、日 |
| 1999.008 | 年和一年中的日子 |
| 99008 | 年和一年中的日子 |
| J2451187 | 儒略日 |
| January 8, 99 BC | 公元前的 99 年 |
3.5.1.2. time [ ( p ) ] [ without time zone ]
p ) ] [ without time zone ] 按 SQL99,此类型可以写作
time 或
time without time zone。可选精度
p 应在 0 到 13
之间,默认取输入时间字面量的精度。
下面是有效的 time 输入。
表 3.12. 时间输入
| 示例 | 描述 |
|---|---|
| 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 |
| allballs | 和 00:00:00 一样 |
3.5.1.3. time [ ( precision ) ] with time zone
precision ) ] with time zone 此类型由 SQL92
定义,但该定义表现出一些使其用途令人怀疑的特性。在大多数情况下,date、time、timestamp
without time zone 和
timestamp with time zone
的组合应能提供任何应用所需的完整日期/时间功能。
可选精度
p 应在 0 到 13
之间,默认取输入时间字面量的精度。
time with time zone 接受所有对
time 类型合法的输入,再加上一个合法的时区,如下:
表 3.13. 带时区的时间输入
| 示例 | 描述 |
|---|---|
| 04:05:06.789-8 | ISO 8601 |
| 04:05:06-08:00 | ISO 8601 |
| 04:05-08:00 | ISO 8601 |
| 040506-08 | ISO 8601 |
更多时区的示例参见表 3.14。
3.5.1.4. timestamp [ (precision) ] without time zone
precision) ] without time zone timestamp [ (
类型的有效输入由一个日期和一个时间连接而成,其后可跟可选的
p) ] without
time zoneAD 或
BC,再后可跟可选的时区。(见下文。)因此
1999-01-08 04:05:06
是一个符合 ISO
的有效 timestamp without time zone
值。此外,广泛使用的格式
January 8 04:05:06 1999 PST
也被支持。
可选精度
p 应在 0 到 13
之间,默认取输入
timestamp 字面量的精度。
对于 timestamp without time
zone,输入中指定的任何显式时区都会被静默吞掉。也就是说,得到的日期/时间值由输入值中显式的日期/时间字段导出,不随时区调整。
3.5.1.5. timestamp [ (precision) ] with time zone
precision) ] with time zone timestamp
类型的有效输入由一个日期和一个时间连接而成,其后可跟可选的
AD 或
BC,再后可跟可选的时区。(见下文。)因此
1999-01-08 04:05:06 -8:00
是一个符合 ISO
的有效 timestamp 值。此外,广泛使用的格式
January 8 04:05:06 1999 PST
也被支持。
可选精度
p 应在 0 到 13
之间,默认取输入
timestamp 字面量的精度。
表 3.14. 时区输入
| 时区 | 描述 |
|---|---|
| PST | 太平洋标准时间 |
| -8:00 | PST的ISO-8601偏移 |
| -800 | PST的ISO-8601偏移 |
| -8 | PST的ISO-8601偏移 |
3.5.1.6. interval [ ( precision ) ]
precision ) ] interval值可以用下列语法书写:
Quantity Unit [Quantity Unit...] [Direction] @ 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 到 13
之间,默认取输入字面量的精度。
3.5.1.7. 特殊值
下面的函数与 SQL 兼容,可用作相应数据类型的日期或时间输入:CURRENT_DATE、CURRENT_TIME、CURRENT_TIMESTAMP。后两个函数接受可选的精度说明。
PostgreSQL 还为方便使用支持几种特殊常量。
表 3.15. 特殊日期/时间常量
| 常量 | 描述 |
|---|---|
| epoch | 1970-01-01 00:00:00+00(Unix系统时间0) |
| infinity | 晚于其他有效时间 |
| -infinity | 早于其他有效时间 |
| invalid | 非法输入 |
| now | 当前事务时间 |
| today | 今天午夜 |
| tomorrow | 明天午夜 |
| yesterday | 昨天午夜 |
| zulu, allballs, z | 00:00:00.00 GMT |
'now'
在值首次被解释时求值。
注意
从 PostgreSQL 7.2 版开始,'current' 不再被支持作为日期/时间常量。以前,'current' 被存储为一个特殊值,只有在用于表达式或类型转换时才求值为 'now'。
3.5.2. 日期/时间输出 #
输出格式可以用
SET DateStyle
设为四种风格之一:ISO
8601、SQL(Ingres)、传统
PostgreSQL 和德式。默认是
ISO 格式。
表 3.16. 日期/时间输出风格
| 样式说明 | 描述 | 示例 |
|---|---|---|
| 'ISO' | ISO-8601 标准 | 1997-12-17 07:37:16-08 |
| 'SQL' | 传统样式 | 12/17/1997 07:37:16.00 PST |
| 'PostgreSQL' | 原始样式 | Wed Dec 17 07:37:16 1997 PST |
| 'German' | 地区样式 | 17.12.1997 07:37:16.00 PST |
date 和
time 风格的输出当然只是上述示例中相应的日期或时间部分。
SQL 风格有欧式和非欧式(美式)两种变体,它们决定月跟在日后还是日跟在月后。(关于此设置如何影响输入值的解释,另见第 3.5.1 节。)
表 3.17. 日期顺序惯例
| 样式说明 | 描述 | 示例 |
|---|---|---|
| European | day/month/year | 17/12/1997 15:37:16.00 MET |
| US | month/day/year | 12/17/1997 07:37:16.00 PST |
interval 的输出与输入格式相似,区别在于像
week 或
century 这样的单位会被转换为年和天。ISO
模式下输出形如
[ Quantity Units [ ... ] ] [ Days ] Hours:Minutes [ ago ]
有几种方法可以影响日期/时间类型的外观:
postmaster 启动时后端直接使用的
PGDATESTYLE环境变量。会话启动时前端 libpq 使用的
PGDATESTYLE环境变量。SET DATESTYLESQL 命令。
3.5.3. 时区 #
PostgreSQL 力求在典型用法上与 SQL92 定义兼容。但 SQL92 标准对日期和时间类型及能力有一种奇怪的组合。两个明显的问题是:
尽管
date类型没有关联的时区,time类型却可以有关联的时区。现实世界中的时区若不同时关联日期和时间就可能没有意义,因为偏移量在一年中可能随夏令时边界而变化。默认时区被指定为相对 GMT/UTC 的固定整数偏移。在跨 DST 边界进行日期/时间运算时无法适应夏令时。
为解决这些困难,我们建议在使用时区时选用同时包含日期和时间的日期/时间类型。我们建议不要使用
SQL92 的
time
with time zone 类型(尽管为了旧应用以及与其他
RDBMS 实现的兼容,PostgreSQL
支持它)。对于只包含日期或只包含时间的类型,PostgreSQL
假定使用你的本地时区。此外,时区支持源自底层操作系统的时区能力,因此可以处理夏令时和其他预期行为。
对于 1902 到 2038 年之间的日期,PostgreSQL 从底层操作系统获得时区支持(接近 Unix 风格系统的典型日期界限)。在此范围之外,所有日期都假定以协调世界时(UTC)指定和使用。
所有日期和时间在内部都以 UTC(传统上称为格林尼治标准时间 GMT)存储。时间在发送给客户端前端之前会被转换为数据库服务器上的本地时间,因此默认情况下采用服务器时区。
有几种方法可以影响时区行为:
postmaster 启动时后端直接使用
TZ环境变量作为默认时区。如果在客户端设置了
PGTZ环境变量,libpq 会在连接时用它向后端发送SET TIME ZONE命令。SQL 命令
SET TIME ZONE设置会话的时区。SQL92 的限定词
timestampAT TIME ZONE 'zone'其中
zone可以指定为文本时区(例如'PST')或区间(例如INTERVAL '-08:00')。
注意
如果指定了无效的时区,时区会变成 GMT(至少在大多数系统上如此)。
注意
如果设置了运行时选项
AUSTRALIAN_TIMEZONES,那么
CST 和
EST 指的是澳大利亚时区而不是美国时区。
3.5.4. 内部实现 #
PostgreSQL 在所有日期/时间计算中使用儒略日。它们有一个好的特性:在假定一年长度为 365.2425 天的前提下,能正确预测/计算从公元前 4713 年到遥远未来的任何日期。
19 世纪之前的日期约定读起来很有意思,但它们并不足够一致,不值得写进日期/时间处理器中。