Lui*_*uiz 5 postgresql timezone date-arithmetic dst
我们有一个表格,里面装满了来自另一个系统的遗留报告的数据。该表的列反映了报告的相同结构。
以下是表的缩写结构:
CREATE TABLE IF NOT EXISTS LEGACY_TABLE (
REPORT_DATE DATE NOT NULL,
EVENT_ID BIGINT PRIMARY KEY NOT NULL,
START_HOUR TIMESTAMP WITHOUT TIME ZONE,
END_HOUR TIME WITHOUT TIME ZONE,
EXPECTED_HOUR TIME WITHOUT TIME ZONE
);
Run Code Online (Sandbox Code Playgroud)
我们正在重构这个表来处理不同客户端的不同时区。新结构将类似于:
CREATE TABLE IF NOT EXISTS LEGACY_TABLE (
REPORT_DATE DATE NOT NULL,
EVENT_ID BIGINT PRIMARY KEY NOT NULL,
START_HOUR TIMESTAMP WITH TIME ZONE,
END_HOUR TIME WITH TIME ZONE,
EXPECTED_HOUR TIME WITH TIME ZONE
);
Run Code Online (Sandbox Code Playgroud)
这些小时字段表示由 REPORT_DATE 列表示的一天中的特定时间点。我的意思是每个 TIME 列都代表 REPORT_DATE 中指定的一天中的一个时刻。
其他一些需要考虑的点:
但现在问题来了。这些列的值用于在我们的系统中多次计算另一个值,如下所示:
START_HOUR - END_HOUR (the result of this operation is currently being casted to TIME WITHOUT TIME ZONE)
START_HOUR < END_HOUR
START_HOUR + EXPECTED_HOUR
EXPECTED_HOUR - END_HOUR
EXPECTED_HOUR < '05:00'
Run Code Online (Sandbox Code Playgroud)
经过一些研究,我发现不建议使用该类型TIME WITH TIME ZONE(Postgres time with time zone equal),现在我对重构此表以处理不同时区和处理不同列的最佳方法有些困惑我们需要的操作。
除此之外,我已经知道减去两列 type 是安全的TIMESTAMP WITH TIME ZONE。这个减法运算考虑了 DST 的变化(用时区减去时间戳类型的两列),但其他的呢?还有从 TIMESTAMP 中减去 TIME 的那个?。
关于表重构,我们应该使用TIME WITH TIME ZONE吗?我们应该继续使用TIME WITHOUT TIME ZONE吗?或者最好TIME完全忘记类型并将日期与时间结合起来并将列更改为TIMESTAMP WITH TIME ZONE?
我认为这些问题是相关的,因为我们选择使用的新列类型将定义我们如何操作列。
你断言:
每个 TIME 列代表 中指定的一天中的一个时刻
REPORT_DATE。
所以你永远不会在同一行内越过日期变更线。我建议保存 1x date3xtime和时区(作为text或 FK 列):
CREATE TABLE legacy_table (
event_id bigint PRIMARY KEY NOT NULL
, report_date date NOT NULL
, start_hour time
, end_hour time
, expected_hour time
, tz text -- time zone
);
Run Code Online (Sandbox Code Playgroud)
就像您已经发现的那样,通常应该避免timetz( time with time zone)。它不能与DST规则妥善处理(d aylight小号AVING牛逼IME)。
所以基本上你已经有了。只需从 中删除日期组件start_hour,那是死运费。投射timestamp到time以截断日期。喜欢:(timestamp '2018-03-25 1:00:00')::time
tz可以是AT TIME ZONE构造接受的任何字符串,但为了可靠地处理不同的时区,最好只使用时区名称。name您在系统目录中pg_timezone_names找到的任何内容。
为了优化存储,您可以在一个小的查找表中收集允许的时区名称并替换tz text为tz_id int REFERENCES my_tz_table.
有和没有 DST 的两个示例行:
CREATE TABLE legacy_table (
event_id bigint PRIMARY KEY NOT NULL
, report_date date NOT NULL
, start_hour time
, end_hour time
, expected_hour time
, tz text -- time zone
);
Run Code Online (Sandbox Code Playgroud)
出于表示目的或计算目的,您可以执行以下操作:
INSERT INTO legacy_table VALUES
(1, '2018-03-25', '1:00', '3:00', '2:00', 'Europe/Vienna') -- sadly, with DST
, (2, '2018-03-25', '1:00', '3:00', '2:00', 'Europe/Moscow'); -- Russians got rid of DST
Run Code Online (Sandbox Code Playgroud)
您可以根据需要创建一个或多个视图以方便地显示字符串。该表用于存储您需要的信息。
注意括号!否则,由于运算符优先级,运算符+将在之前绑定。AT TIME ZONE
看看结果:
db<>在这里摆弄
由于时间在维也纳被操纵(就像任何适用愚蠢 DST 规则的地方一样),您会得到“令人惊讶”的结果。
有关的:
| 归档时间: |
|
| 查看次数: |
1154 次 |
| 最近记录: |