PostgreSQL、pgAdmin、Java:如何使它们全部为 UTC?

问题描述 投票:0回答:4

我如何确保围绕 PostgreSQL 的整个开发环境不会与本地时区发生冲突。为简单起见,我需要 100% 确定每个时间(标记)值都是 UTC。当我使用

timestamp without time zone
函数插入带有
CURRENT_TIMESTAMP
(!) 的行时,我不得不意识到情况并非如此,即使我从未指定过任何时区信息。

有没有任何分步手册可以帮助我摆脱时区?

java postgresql timezone timestamp utc
4个回答
4
投票

首先了解 Postgres 如何处理时间戳和时间:

你不能“没有”时区。您可以使用类型

timestamp [without time zone]
进行操作,但您的客户端中仍然有一个时区。

您的陈述:

当我使用

timestamp without time zone
函数插入带有
CURRENT_TIMESTAMP
(!) 的行时...

是形容词中的矛盾。

CURRENT_TIMESTAMP
返回
timestamp with time zone
(!)。如果您只是将其强制转换(或自动强制)到
timestamp [without time zone]
,则时区偏移量将被截断而不是应用。您将获得当前会话的
timezone
设置的当地时间,而不是 UTC。考虑:

SELECT CURRENT_TIMESTAMP AT TIME ZONE 'UTC'
     , CURRENT_TIMESTAMP::timestamp

除非您的本地时区设置是“UTC”或“伦敦”之类的内容,否则这两个表达式将返回不同的值。

如果您想保存在您的时区中看到的文字值,请使用以下之一:

SELECT CURRENT_TIMESTAMP::timestamp
     , now()::timestamp
     , LOCALTIMESTAMP;

如果您想保存以 UTC 表示的时间点,请使用以下选项之一:

SELECT CURRENT_TIMESTAMP AT TIME ZONE 'UTC'
     , now() AT TIME ZONE 'UTC;

2
投票

您陷入了一个重大误解:时间戳不包含任何时区信息!有关详细信息,请参阅我的其他答案此处。换句话说,您的整个开发环境已经不使用时区。您需要确保的唯一一件事是,当时间的文本表示形式转换为时间戳(反之亦然)时,进行转换的人知道文本表示形式表示的时区。对于其他所有内容,时区是无关紧要的。

这都怪Sun!他们认为,如果包含在时间戳对象本身内部将时间戳与文本相互转换的方法(首先使用

Date
,然后使用
Calendar
),对开发人员来说会很方便。由于此转换需要时区,因此他们认为如果同一个类存储时区会更加方便,这样您就不必每次进行转换时都传递它。这助长了 Java 有史以来最普遍(最具破坏性)的误解之一。我不知道用其他语言开发的人有什么借口。也许他们只是愚蠢。


0
投票

声明日期列“timestamptz”或“带时区的时间戳”。

您是否还询问转换未存储时间戳的现有数据?


0
投票

类型错误,请使用
TIMEZONE WITH TIME ZONE

无时区的时间戳

Postgres 和 SQL 标准中的

TIMESTAMP WITHOUT TIME ZONE
数据类型表示日期和时间,但没有任何时区或相对 UTC 偏移量的概念。所以这个类型不能代表一个时刻,不是时间轴上的一个点。

您向此类列提交的任何时区或偏移信息都将被忽略。

跟踪特定时刻时,请使用另一种类型,

TIMESTAMP WITH TIME ZONE
。在 Postgres 中,您向此类列提交的任何时区或偏移信息都将用于调整为 UTC(然后被丢弃)。

为了简单起见,我需要 100% 确定每个时间(标记)值都是 UTC。

然后使用类型为

TIMESTAMP WITH TIME ZONE
的列。

有任何分步手册可以帮助我摆脱时区吗?

您确实不想想要摆脱时区(和偏移量),因为这意味着您将留下不明确的日期和时间。例如,今年 1 月 23 日的中午无法告诉我们您指的是日本东京的中午、法国图卢兹的中午还是美国俄亥俄州托莱多的中午。这些都是不同的时刻,相隔几个小时。

java.time

使用 JDBC 4.2,我们可以交换 java.time 对象,而不是可怕的遗留日期时间类。

OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;

检索。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

这些值均采用 UTC 格式,偏移量为零时-分-秒。

Table of date-time types in Java (both legacy and modern) and in standard SQL

谨防中间件

请注意,许多工具和中间件(例如 PgAdmin)会欺骗您。在一个善意的反功能中,他们对从数据库中提取的数据应用了默认时区。

TIMESTAMP WITH TIME ZONE
类型的值在 Postgres 中始终存储在 UTC 中。但您的工具可能会像在
America/Montreal
、或
Pacific/Auckland
或任何其他默认时区一样报告该值。

我建议始终将此类工具中的默认时区设置为 UTC。

© www.soinside.com 2019 - 2024. All rights reserved.