在PostgreSQL timestamptz类型中保留时区

时间:2013-11-28 21:23:30

标签: postgresql timezone timestamp postgresql-9.3

符合ISO8601标准的日期时间

2004-10-19 10:23:54+02

是否可以将具有+02偏移量的值反映在存储的列值中,并在选择时保留该值?

从我对appropriate section of the docs Postgres'的读取中,默认行为是转换为UTC,此时原始偏移量将丢失。这当然是我所看到的。

通过无法添加任何特殊tz转换的ORM访问数据,因此我真的需要简单地将日期时间与原始偏移量一起存储,并在选择时反映该值。

对于任何想要及时告诉我它是同一个实例的人来说,保存这个值对这些数据具有重要意义。

3 个答案:

答案 0 :(得分:15)

正如您已经发现的那样, 时区 根本不会保存在Postgres日期/时间类型中,甚至不会保存在timestamptz中。它的作用分别只是输入修饰符或输出修饰符。仅保存值(时间点)。这个相关答案的详细信息如下:

因此,如果要保留输入字符串的那一部分,则必须从字符串中提取它并自行保存。我会使用像这样的表:

CREATE TABLE tstz
 ...
 , ts timestamp    -- without time zone
 , tz text
)

tztext,可以包含数字偏移量以及时区缩写,或时区名称

困难在于根据解析器遵循的所有各种规则以及不会轻易破坏的方式提取时区部分。 使解析器完成工作,而不是自己编写程序。考虑一下这个演示:

WITH ts_literals (tstz) AS (
   VALUES ('2013-11-28 23:09:11.761166+03'::text)
         ,('2013-11-28 23:09:11.761166 CET')
         ,('2013-11-28 23:09:11.761166 America/New_York')
   )
SELECT tstz
      ,tstz::timestamp AS ts
      ,right(tstz, -1 * length(tstz::timestamp::text)) AS tz
FROM   ts_literals;

SQL Fiddle.

在日期和时间之间使用或不使用T。关键逻辑在这里:

right(tstz, -1 * length(tstz::timestamp::text)) AS tz

在修剪解析器标识为日期/时间组件的长度之后,取一个时间戳字符串的内容。正如你所说,这取决于输入:

  

验证ISO8601字符串

答案 1 :(得分:2)

Java开发人员可以将Joda Time Jadira UserType PersistentDateTimeAndZone结合使用。例如:

@Basic(optional = false)
@Columns(columns = { @Column(name = "modificationtime"),
        @Column(name = "modificationtime_zone") })
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTimeAndZone")
@Index(name = "payment_modificationtime_idx")
private DateTime modificationTime = null;

在此示例中,DateTime信息位于2列中:

  1. modificationtime timestamp without time zone以UTC时区存储时间戳
  2. modificationtime_zone varchar(255)将时区ID存储为字符串(例如America/Caracas
  3. 虽然Joda Time和Jadira(和Hibernate)特定于Java(并且是事实上的方法),但是可以应用上述构造RDBMS列以存储时间戳和时区的方法任何编程语言。

答案 2 :(得分:1)

原生帖子date/time datatypes不会为您保留输入时区。如果您需要将其作为数据库中的时间戳进行查询并显示原始信息,则必须以某种方式存储这两条信息。

我打算建议你的ORM可以定义自定义膨胀/收缩方法来处理魔法,但显然它不能。您应该指出您正在使用的ORM。

您可以让ORM在数据库中存储/检索字符串,并使用Postgres中的trigger将其转换为存储在执行数据库端查询时使用的另一列中的时间戳。如果您有许多具有此类数据的表,那可能有点笨拙。

如果您确实希望数据位于数据库的单个列中,则可以在Postgres中定义composite type,但您的ORM可能无法处理它们。