↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1
历史版本。 PostgreSQL 7.4 已结束支持。 请参阅 当前版本手册.

8.5. 日期/时间类型 #

PostgreSQL 支持全套 SQL 日期和时间类型,如表 8.9所示。

表 8.9. 日期/时间类型

名字存储尺寸描述低值高值精度
timestamp [ (p) ] [ without time zone ]8字节日期和时间4713 BC5874897 AD1微秒 / 14位
timestamp [ (p) ] with time zone8字节包括日期和时间,有时区4713 BC5874897 AD1微秒 / 14位
interval [ (p) ]12字节时间间隔-178000000年178000000年1微秒
date4字节仅日期4713 BC32767 AD1日
time [ (p) ] [ without time zone ]8字节仅一天中的时间00:00:00.0023:59:59.991微秒
time [ (p) ] with time zone12字节仅一天中的时间,带时区00:00:00.00+1223:59:59.99-121微秒

注意

在 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是内部使用的低精度类型。不推荐在应用中使用这些类型;这些内部类型可能在将来的版本中消失。

8.5.1. 日期/时间输入 #

日期和时间输入几乎可以采用任何合理的格式,包括 ISO 8601、SQL 兼容格式、传统 POSTGRES 格式等。对于某些格式,日期输入中月、日、年的顺序可能有歧义,因此支持指定所期望的这些字段的顺序。将 datestyle 参数设为 MDY 可选择月-日-年解释,设为 DMY 可选择日-月-年解释,设为 YMD 可选择年-月-日解释。

PostgreSQL 在处理日期/时间输入方面,比 SQL 标准要求的更灵活。有关日期/时间输入的精确解析规则,以及可识别的文本字段(包括月份、星期几和时区),请参见附录 B。

请记住,任何日期或时间字面值输入都必须像文本字符串一样用单引号括起来。更多信息请参见第 4.1.2.4 节。SQL 要求使用下列语法:

type [ (p) ] 'value'

其中 p 是可选的精度说明,给出秒字段中保留的小数位数。精度可用于 time、timestamp 和 interval 类型,允许的取值范围见上文。如果在常量声明中没有指定精度,则默认采用该字面值本身的精度。

8.5.1.1. 日期

表 8.10显示了date类型可能的输入方式。

表 8.10. 日期输入

示例描述
January 8, 1999在任何datestyle输入模式下都无歧义
1999-01-08ISO 8601;任何模式下的1月8日(推荐格式)
1/8/1999MDY模式中的1月8日;DMY模式中的8月1日
1/18/1999MDY模式中的1月18日;在其他模式中被拒绝
01/02/03MDY模式中的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-08YMD模式中的1月8日,否则错误
08-Jan-991月8日,除了在YMD模式中错误
Jan-08-991月8日,除了在YMD模式中错误
19990108ISO 8601;任何模式中的1999年1月8日
990108ISO 8601;任何模式中的1999年1月8日
1999.008年和一年中的日子
J2451187儒略日
January 8, 99 BC公元前99年

8.5.1.2. 时间

一天中的时间类型包括 time [ (p) ] without time zone 和 time [ (p) ] with time zone。单独写 time 等效于 time without time zone。

这些类型的有效输入由一个一天中的时间,加上一个可选时区组成(见表 8.11和表 8.12)。如果在 time without time zone 的输入中指定了时区,它会被静默忽略。

表 8.11. 时间输入

示例描述
04:05:06.789ISO 8601
04:05:06ISO 8601
04:05ISO 8601
040506ISO 8601
04:05 AM和04:05一样,AM并不影响值
04:05 PM和16:05一样;输入的小时必须 <= 12
04:05:06.789-8ISO 8601
04:05:06-08:00ISO 8601
04:05-08:00ISO 8601
040506-08ISO 8601
04:05:06 PST名称指定的时区

表 8.12. 时区输入

示例描述
PST太平洋标准时间
-8:00PST的ISO-8601偏移
-800PST的ISO-8601偏移
-8PST的ISO-8601偏移
zuluUTC的军方缩写
zzulu的缩写形式

8.5.1.3. 时间戳

时间戳类型的有效输入由一个日期和一个时间连接而成,其后可跟可选的 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。

8.5.1.4. 间隔

interval值可以用下列语法书写:

[@] quantity unit [quantity unit...] [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 之间,默认为输入字面量的精度。

8.5.1.5. 特殊值

下面的函数与 SQL 兼容,可用作相应数据类型的日期或时间值:CURRENT_DATE、CURRENT_TIME、CURRENT_TIMESTAMP、LOCALTIME、LOCALTIMESTAMP。后四个函数接受可选的精度说明。(另见第 9.8.4 节。)

PostgreSQL 还为方便使用支持几种特殊日期/时间输入值,如表 8.13所示。值 infinity 和 -infinity 在系统内部有特殊的表示并以相同方式显示;其余的只是记法上的简写,读取时会被转换为普通的日期/时间值。所有这些值都被当作普通常量处理,需要写成单引号括起来的形式。

表 8.13. 特殊日期/时间输入

输入字符串有效类型描述
epochdate, timestamp1970-01-01 00:00:00+00(Unix系统时间0)
infinitytimestamp晚于所有其他时间戳
-infinitytimestamp早于所有其他时间戳
nowdate, time, timestamp当前事务的开始时间
todaydate, timestamp今天午夜
tomorrowdate, timestamp明天午夜
yesterdaydate, timestamp昨天午夜
allballstime00:00:00.00 UTC

8.5.2. 日期/时间输出 #

日期/时间类型的输出格式可以设为四种样式之一:ISO 8601、SQL(Ingres)、传统的 POSTGRES 和 German,这通过命令SET datestyle设置。默认是ISO格式。(SQL标准要求使用 ISO 8601 格式。之所以存在名为“SQL”的输出格式,只是历史原因。)表 8.14展示了各种输出样式的示例。date和time类型的输出当然只包含给定示例中相应的日期部分或时间部分。

表 8.14. 日期/时间输出风格

样式说明描述示例
ISOISO 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, DMYday/month/year17/12/1997 15:37:16.00 CET
SQL, MDYmonth/day/year12/17/1997 07:37:16.00 PST
Postgres, DMYday/month/yearWed 17 Dec 07:37:16 1997 PST

interval 的输出与输入格式相似,区别在于像 century 或 wek 这样的单位会被转换为年和天,并且 ago 会被转换为适当的符号。在 ISO 模式下输出形如

[ quantity unit [ ... ] ] [ days ] [ hours:minutes:sekunden ]

用户可以用 SET datestyle 命令、postgresql.conf 配置文件中的 datestyle 参数,或服务器/客户端上的 PGDATESTYLE 环境变量来选择日期/时间风格。格式化函数 to_char(见第 9.7 节)也可作为一种更灵活的日期/时间输出格式化手段。

8.5.3. 时区 #

时区及时区惯例受政治决策的影响,而不只是地球几何。世界各地的时区在 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。

8.5.4. 内部实现 #

PostgreSQL在所有日期/时间计算中使用儒略日。这带来一个有用的特性:在假定一年长度为 365.2425 天的前提下,能够正确计算从公元前 4713 年到遥远未来的日期。

19 世纪之前的日期约定读起来很有意思,但它们并不足够一致,不值得写进日期/时间处理器中。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.