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

时间:2013-05-01 23:20:10

标签: java postgresql timezone timestamp utc

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

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

4 个答案:

答案 0 :(得分:3)

这需要先了解。我写了一篇关于PostgreSQL如何处理时间戳和时区的综合答案:
Ignoring timezones altogether in Rails and PostgreSQL

你不能“不”拥有时区。您可以使用timestamp [without time zone]类型进行操作,但您的客户端仍有时区。

您的陈述:

  

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

contradictio in adjectoCURRENT_TIMESTAMP返回timestamp with time zone(!)。如果您只是将其强制转换(或将其自动强制转换为)timestamp [without time zone],则时区偏移将被截断而不是应用。您获得本地时间(无论会话的当前时区设置是什么)而不是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;

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

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

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

答案 3 :(得分: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/MontrealPacific/Auckland或任何其他默认时区中报告该值。

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