时区和时区习惯不仅仅受地球几何形状的影响,还受到政治决定的影响。到了 19 世纪,全球的时区变得稍微标准化了些,但是还是易于遭受随意的修改,部分是因为夏时制规则。PostgreSQL 目前支持 1902 年到 2038 年之间的夏时制信息(对应于传统 Unix 系统时间的完整跨度)。如果时间超过这个范围,那么假设时间是所选时区的"标准时间",不管它们落在哪个年份里面。

PostgreSQL 在典型应用中尽可能与 SQL 的定义相兼容。但 SQL 标准在日期/时间类型和功能上有一些奇怪的混淆。两个显而易见的问题是:

date 类型与时区没有联系,而 time 类型却有或可以有。然而,现实世界的时区只有在与时间和日期都关联时才有意义,因为时间偏移量(时差)可能因为实行类似夏时制这样的制度而在一年里有所变化。

缺省的时区用一个数字常量表示与 UTC 的偏移(时差)。因此,当跨 DST(夏时制)界限做日期/时间算术时,我们根本不可能把夏时制这样的因素计算进去。

为了克服这些困难,我们建议在使用时区的时候,使用那些同时包含日期和时间的日期/时间类型。我们建议不要使用 time with time zone 类型(尽管 PostgreSQL 出于合理应用以及为了与其它 RDBMS 兼容的考虑支持这个类型)。PostgreSQL 假设你用于任何类型的本地时区都只包含日期或时间(而不包含时区)。

在系统内部,所有日期和时间都用全球统一时间 UTC 格式存储,时间在发给客户前端前由数据库服务器根据 timezone 配置参数声明的时区转换成本地时间。

PostgreSQL 允许你用三种方法指定时区:

完整的时区名。例如 America/New_York 。所有可以识别的时区名在 pg_timezone_names 视图中列出(参见节43.49)。PostgreSQL 使用广泛使用的 zic 时区数据,所以这些时区名在其它软件里也能被轻松的识别。

时区缩写。例如 PST 。这种缩写名通常只是定义了相对于 UTC 的偏移量,而前一种完整的时区名可能还隐含着一组夏时制转换规则。所有可以识别的时区缩写在 pg_timezone_abbrevs 视图中列出(参见节43.48)。你不能使用时区缩写来设置 timezone 配置参数,但是你可以在日期/时间输入值中结合 AT TIME ZONE 操作符使用时区缩写。

除完整的时区名及其缩写之外,PostgreSQL 还接受 POSIX 风格的 STDoffset 或 STDoffsetDST 格式的时区,其中的 STD 是时区缩写、offset 是一个相对于 UTC 的小时偏移量、DST 是一个可选的夏时制时区缩写(假定相对于给定的偏移量提前一小时)。例如,如果 EST5EDT 不是一个已识别的时区名,那么它将等同于美国东部时间,如果存在夏时制时区,那么它将按照美国的时区规则使用,因此这个特性在北美州之外没什么用处。需要提醒的是这个特性会导致悄悄的接受不合理的输入,因为它不对时区缩写的合理性做检查。例如,SET TIMEZONE TO FOOBAR0 不会报错,而是使系统使用 GMT 。

完整的时区名与时区缩写在理论与实践之间存在差异:时区缩写总是代表一个相对于 UTC 的固定偏移量,然而大多数完整的时区名隐含着一个本地夏令时规则,因此就有可能有两个相对于 UTC 的不同偏移量。

总体而言,PostgreSQL 8.2 版本以后时区名在所有情况下都是大小写无关的。而之前的版本在某些情况下是大小写敏感的。

无论是完整的时区名还是时区缩写都不是硬连接进服务器的,它们都是从安装目录下的 .../share/timezone/ 和 .../share/timezonesets/ 配置文件中获取的(参见章B.3)

可以在 postgresql.conf 文件里设置 timezone 配置参数,或者用任何其它在章17描述的标准方法。除此之外,还有好几种特殊方法可以设置它:

如果既没有在 postgresql.conf 里也没有在命令行开关上声明 timezone ,那么服务器将试图使用服务器主机上的 TZ 环境变量作为服务器的缺省时区。如果 TZ 没有定义或者是 PostgreSQL 不认识的时区名,那么服务器将试图通过检查 C 库函数 localtime() 的行为来判断操作系统的缺省时区。缺省时区是按照最接近 PostgreSQL 的已知时区的原则来选择的。

使用 SQL 命令 SET TIME ZONE 为会话设置时区,这是 SET TIMEZONE TO 的一个可选的拼写方式,更加兼容标准。

如果在客户端设置了 PGTZ 环境变量,那么 libpq 在连接时将使用这个环境变量给后端发送一个 SET TIME ZONE 命令。