PostgreSQL/JDBC和TIMESTAMP与TIMESTAMPTZ

rob*_*lco 16 postgresql jpa jdbc

最近我和JPA一起经历了很多关于Timestamps的痛苦.我发现我的很多问题已经通过TIMESTAMPTZ用于我的字段而不是TIMESTAMP来清除.我的服务器是UTC,而我的JVM是PST.使用TIMESTAMP WITHOUT TIMEZONE时,JPA几乎不可能对数据库中的UTC值进行标准化.

对我来说,我将这些字段用于"用户何时创建","他们上次使用设备的时间","他们最后一次收到警报的时间"等等.这些通常是事件,因此它们是实例时间种类的价值观.因为他们现在将通过TIMESTAMPTZ,如果我不想要它们,我总是可以查询它们的特定区域.

所以我的问题是,对于Java/JPA/PostgreSQL服务器,什么时候我想在TIMESTAMPTZ上使用TIMESTAMP?有什么用例呢?现在我很难理解为什么我想要使用TIMESTAMP,因为我担心我没有抓住它的价值.

Bas*_*que 28

一般使用TIMESTAMPZ

以下是Postgres专家David E. Wheeler在博客文章中给出的建议,其标题说明了一切:
始终使用TIMESTAMP与时区(TIMESTAMPZ)

如果您要跟踪实际时刻,时间轴上的特定点,请使用TIMESTAMP WITH TIME ZONE.

一个例外:分区

Wheeler唯一的例外是在时间戳上进行分区时,由于技术限制.一个罕见的例外对于我们大多数人.

有关分区的信息,请参阅doc并查看Wiki.

用词不当

数据类型名称timestamp with time zonetimestamp without time zone用词不当.在这两种情况下,日期时间值都以UTC格式存储(无时区偏移).再读一遍前一句.UTC,永远."带时区"短语的意思是"注意时区",而不是"将时区与此值一起存储".类型之间的区别在于是否应在存储(INSERT或UPDATE)或检索(SELECT查询)期间应用任何时区.(Postgres描述了这种行为 - 其他数据库在这方面差异很大.)

更确切地说,应该说TIMESTAMP WITHOUT TIME ZONE存储没有时区的日期时间值.但是没有任何时间框架参考,任何查看该数据的人都必须假设(希望,祈祷?)这些值是UTC.但是,再次,因为你应该几乎从不使用这种类型.

仔细阅读文档,并进行一些实验以阐明您的理解.

不分区

如果您想存储可能时间的一般概念而不是特定时刻,请使用其他类型,TIMESTAMP WITHOUT TIME ZONE.

例如,今年圣诞节将于2017年12月25日的第一时间开始.这将2017-12-25T 00:00:00没有时区指标,也不会偏离UTC.这个值只是对可能时刻的模糊概念.在我们应用时区(或偏移)之前,它没有任何意义.所以我们使用它存储TIMESTAMP WITHOUT TIME ZONE.

圣诞老人特殊事件后勤部的精灵们将时区作为他们规划过程的一部分.目前最早的时区Pacific/Kiribati比UTC早14个小时.精灵计划圣诞老人首次到达那里.精灵安排了一个飞行计划,将驯鹿带到其他时区不久的时间段,例如Pacific/Auckland.随着每个区域的午夜到来,它们继续向西移动.几个小时后Asia/Kolkata,仍然在Europe/Paris更晚的时间America/Montreal,等等.

这些特定的传递时刻中的每一个都将由精灵使用进行记录WITH TIME ZONE,而圣诞节的一般概念将被存储为WITHOUT TIME ZONE.

商业应用程序中的另一个用途WITHOUT TIME ZONE是安排超过几周的约会.世界各地的政治家们对于弄乱时钟和重新定义时区规则有着莫名的偏爱.他们加入夏令时(DST),离开夏令时,在另一个日期开始夏令时,或在另一个日期结束夏令时,或将他们的时钟移动15分钟或半小时.所有这些都是在过去几年中由土耳其,美国,俄罗斯,委内瑞拉和其他国家完成的.

政客们经常在没有预先警告的情况下做出这些改变.因此,如果您计划在13:00进行为期六个月的牙科预约,那么应该将其存储为TIMESTAMP WITHOUT TIME ZONE或者政治家可以有效地将您的预约更改为中午,下午2点或13:30.


JB *_*zet 14

您可以使用它来表示Joda-Time和新的Java 8时间API调用的内容LocalDateTime.A LocalDateTime不代表时间轴上的精确点.它只是一组字段,从一年到几纳秒.它是"日期的描述,用于生日,结合在挂钟上看到的当地时间".

例如,您可以使用它来表示您的确切出生日期是1975-07-19下午6点.或者说,在全世界范围内,2015-01-01 00:00庆祝下一个新的一年.

为了表示精确的时刻,就像阿姆斯特朗在月球上行走的那一刻,带有时区的时间戳确实更合适.无论JVM的时区和数据库的时区如何,它都应该返回正确的时刻.

  • 只是检查我的理解,不是为了纠正你,但听起来甚至生日会更好作为TIMESTAMPTZ,除非我希望我的生日在世界各地都是一样的,无论我在哪个时区.虽然新的一年显然需要对于任何地方都不同,不能表示为单个TIMESTAMPTZ.谢谢,我想你终于穿透了我厚厚的头骨.这些东西(尤其是JPA)让我疯狂. (2认同)

asp*_*man 6

更新上述答案:由于修剪,分区在 PG11 中不再是特殊情况。

https://www.postgresql.org/docs/11/ddl-partitioning.html#DDL-PARTITION-PRUNING

个人成功测试了针对 PG11 AWS RDS 的查询。另外,官方 PG wiki 指出使用timestamp without timezone是一个坏主意:

https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_timestamp_.28without_time_zone.29_to_store_UTC_times