5

我如何确保围绕 PostgreSQL 的整个开发环境不会与本地时区混为一谈。为简单起见,我需要 100% 确定每个时间(戳记)值都是 UTC。当我使用该函数插入带有timestamp without time zone(!)的行时,CURRENT_TIMESTAMP我不得不意识到情况并非如此,即使我从未指定任何时区信息。

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

4

4 回答 4

3

这需要先了解。我在这里写了一个关于 PostgreSQL 如何处理时间戳和时区的综合答案:
在 Rails 和 PostgreSQL 中完全忽略时区

您不能“没有”时区。您可以使用 type 进行操作timestamp [without time zone],但您的客户端中仍然有一个时区。

您的声明:

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

是形容词的矛盾CURRENT_TIMESTAMP返回一个timestamp with time zone(!)。如果您只是将它(或自动强制)转换为timestamp [without time zone],则时区偏移量将被截断而不是应用。您将获得本地时间(无论会话的当前时区设置是什么)而不是 UTC。考虑:

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

除非您的本地时区设置是“UTC”或类似“London”,否则这两个表达式会返回不同的值。

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

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

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

SELECT CURRENT_TIMESTAMP AT TIME ZONE 'UTC'
      ,now() AT TIME ZONE 'UTC;
于 2013-05-02T00:46:06.417 回答
2

您已经成为一个重大误解的受害者:时间戳不包含任何时区信息有关详细信息,请参阅我的其他答案。换句话说,您的整个开发环境已经不使用时区。您唯一需要确保的是,当时间的文本表示被转换为时间戳(反之亦然)时,进行转换的对象知道文本表示在哪个时区中表示。对于其他所有内容,时区无关紧要。

我为此责怪孙!他们认为,如果他们在时间戳对象本身中包含用于将时间戳与文本相互转换的方法(首先是 with Date,然后是 with Calendar),对开发人员来说会很方便。由于这种转换需要时区,他们认为如果同一个类存储时区会更加方便,因此您不必每次都通过它进行转换。这助长了 Java 中最普遍(和破坏性)的误解之一。我不知道用其他语言开发的人有什么借口。也许他们只是愚蠢。

于 2013-05-02T00:54:49.733 回答
0

声明日期列“timestamptz”或“timestamp with time zone”。

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

于 2013-05-01T23:25:27.903 回答
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,偏移量为零时分秒。

Java(传统和现代)和标准 SQL 中的日期时间类型表

小心中间件

请注意,许多工具和中间件(例如 PgAdmin)会欺骗您。在一个善意的反特性中,他们将默认时区应用于从数据库中提取的数据。在 Postgres 中,类型TIMESTAMP WITH TIME ZONE的值始终以 UTC 格式存储。但是您的工具可能会在America/Montreal、 或Pacific/Auckland或任何其他默认时区报告该值。

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

于 2020-04-01T20:34:18.433 回答