在 PostgreSQL timestamptz 类型中保留时区

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

对于符合 ISO8601 的日期时间

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

是否可以将该值(具有

+02
偏移量)反映在存储的列值中,并在选择时也保留下来?

根据我对文档的适当部分的阅读Postgres的默认行为是转换为UTC,此时原始偏移量会丢失。这当然是我所看到的。

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

对于任何渴望告诉我这是同一时间实例的人来说,保存该值对于该数据具有重要意义。

postgresql timezone timestamp postgresql-9.3
3个回答
26
投票

正如您自己已经弄清楚的那样,时区根本不会使用Postgres日期/时间类型保存,甚至不会使用

timestamptz
保存。它的作用分别只是输入修饰符或输出修饰符。仅保存值(时间点)。此相关答案中的详细信息:

因此,如果你想保留输入字符串的那部分,你必须从字符串中提取出来并自己保存。我会使用这样的表格:

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

tz
,即
text
,可以保存数字 offset 以及时区 缩写,或时区 name

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

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;

小提琴
老sqlfiddle

日期和时间之间有或没有

T
均可使用。关键逻辑在这里:

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

在修剪解析器识别为日期/时间组件的长度后,获取时间戳字符串的剩余部分。正如您所说,这取决于输入:

经过验证的 ISO 8601 字符串


2
投票

Java 开发人员可以将 Joda TimeJadira 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

虽然 Joda Time 和 Jadira(以及 Hibernate)特定于 Java(并且是“事实上的”方法),但上述构建 RDBMS 列以存储时间戳和时区的方法可以应用于任何编程语言。


1
投票
日期/时间数据类型

不会为您保留输入时区。 如果您需要将其作为数据库中的时间戳进行查询并提供原始信息,则必须以某种方式存储这两条信息。 我本来建议你的 ORM 可以定义自定义的 inflate/deflate 方法来处理魔法,但显然它不能。 您应该指出您正在使用哪个 ORM。

您可以让 ORM 在数据库中存储/检索字符串,并使用 Postgres 中的

trigger

将其转换为存储在执行数据库端查询时使用的另一列中的时间戳。 如果您有很多包含此类数据的表,这可能会有点麻烦。 如果您确实想要数据库中的单个列中的数据,您可以在 Postgres 中定义一个

composite type

,尽管您的 ORM 可能无法处理它们。

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