Difference between timestamps with/without time zone in PostgreSQL
当数据类型为
PostgreSQL文档中包含日期/时间类型的差异。是的,
文档中专门介绍了时区对这些数据类型的影响。差异来自系统对价值的合理了解:
使用时区作为值的一部分,该值可以在客户端中呈现为本地时间。
如果不将时区作为值的一部分,则明显的默认时区为UTC,因此将为该时区呈现该时区。
这种行为取决于至少三个因素:
- 客户端中的时区设置。
- 值的数据类型(即
WITH TIME ZONE 或WITHOUT TIME ZONE )。 - 是否使用特定时区指定该值。
以下是涵盖这些因素组合的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | foo=> SET TIMEZONE TO 'Japan'; SET foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP; TIMESTAMP --------------------- 2011-01-01 00:00:00 (1 ROW) foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE; timestamptz ------------------------ 2011-01-01 00:00:00+09 (1 ROW) foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP; TIMESTAMP --------------------- 2011-01-01 00:00:00 (1 ROW) foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE; timestamptz ------------------------ 2011-01-01 06:00:00+09 (1 ROW) foo=> SET TIMEZONE TO 'Australia/Melbourne'; SET foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP; TIMESTAMP --------------------- 2011-01-01 00:00:00 (1 ROW) foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE; timestamptz ------------------------ 2011-01-01 00:00:00+11 (1 ROW) foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP; TIMESTAMP --------------------- 2011-01-01 00:00:00 (1 ROW) foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE; timestamptz ------------------------ 2011-01-01 08:00:00+11 (1 ROW) |
我试图解释它比引用的PostgreSQL文档更容易理解。
无论名称如何,
TIMESTAMP WITHOUT TIME ZONE 存储本地日期时间(aka.挂历日期和挂钟时间)。据PostgreSQL所知,它的时区是未指定的(尽管您的应用程序可能知道它是什么)。因此,PostgreSQL在输入或输出上不进行与时区相关的转换。如果该值以'2011-07-01 06:30:30' 的形式输入到数据库中,那么在以后显示该值的时区内没有任何数据,它仍然会显示2011年、07月、01日、06小时、30分钟和30秒(以某种格式)。另外,输入中指定的任何偏移量或时区都会被PostgreSQL忽略,因此'2011-07-01 06:30:30+00' 和'2011-07-01 06:30:30+05' 与'2011-07-01 06:30:30' 相同。对于Java开发人员来说,它类似于EDCOX1(12)。TIMESTAMP WITH TIME ZONE 在UTC时间线上存储一个点。它的外观(小时、分钟等)取决于您的时区,但它总是指相同的"物理"瞬间(如实际物理事件的瞬间)。这个输入在内部转换为UTC,这就是它的存储方式。为此,必须知道输入的偏移量,因此当输入不包含显式偏移量或时区(如'2011-07-01 06:30:30' )时,假定它位于PostgreSQL会话的当前时区,否则将使用显式指定的偏移量或时区(如'2011-07-01 06:30:30+05' )。将显示转换为PostgreSQL会话当前时区的输出。对于Java开发人员来说,它类似于EDCOX1×16(虽然分辨率较低),但是对于JDBC和JPA 2.2,您应该将其映射到EDCOX1×17(或EDCOX1 18)或EDCOX1(19)当然。
有人说两个
下面是一个应该有所帮助的例子。如果时间戳带有时区,则可以将该时间戳转换为任何其他时区。如果没有基本时区,它将无法正确转换。
1 2 3 4 | SELECT now(), now()::TIMESTAMP, now() AT TIME ZONE 'CST', now()::TIMESTAMP AT TIME ZONE 'CST' |
输出:
1 2 3 4 5 | -[ RECORD 1 ]--------------------------- now | 2018-09-15 17:01:36.399357+03 now | 2018-09-15 17:01:36.399357 timezone | 2018-09-15 08:01:36.399357 timezone | 2018-09-16 02:01:36.399357+03 |