您断言:
每个 TIME 列代表一天中指定的时刻REPORT_DATE
.
So you never跨越同一行内的日期变更线。我建议保存1xdate
3x time
和时区 (as 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
);
就像你已经发现的那样,timetz (time with time zone) 一般应避免 https://stackoverflow.com/a/20530283/939860。它无法正确处理 DST 规则(daylight saving time).
So 基本上是你已经拥有的。只需删除日期组件即可start_hour
,那是死运费。投掷timestamp
to time
来截断日期。喜欢:(timestamp '2018-03-25 1:00:00')::time
tz
可以是任何接受的字符串AT TIME ZONE https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT构造,但为了可靠地处理不同的时区,最好专门使用时区名称。任何name
你发现在系统目录pg_timezone_names https://www.postgresql.org/docs/current/view-pg-timezone-names.html.
为了优化存储,您可以在小型查找表中收集允许的时区名称并替换tz text
with tz_id int REFERENCES my_tz_table
.
有和没有 DST 的两个示例行:
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
出于表示目的或计算,您可以执行以下操作:
SELECT (report_date + start_hour) AT TIME ZONE tz AT TIME ZONE 'UTC' AS start_utc
, (report_date + end_hour) AT TIME ZONE tz AT TIME ZONE 'UTC' AS end_utc
, (report_date + expected_hour) AT TIME ZONE tz AT TIME ZONE 'UTC' AS expected_utc
-- START_HOUR - END_HOUR
, (report_date + start_hour) AT TIME ZONE tz
- (report_date + end_hour) AT TIME ZONE tz AS start_minus_end
FROM legacy_table;
您可以创建一个或多个views https://www.postgresql.org/docs/current/sql-createview.html以便根据需要轻松显示字符串。该表用于存储您的信息need.
注意括号!否则运营商+
之前会绑定AT TIME ZONE
due to 运算符优先级 https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-PRECEDENCE.
看看结果:
数据库小提琴
由于维也纳的时间受到操纵(就像任何适用愚蠢的 DST 规则的地方一样),您会得到“令人惊讶”的结果。
Related:
- 选择计划项目时考虑 Postgres 中的 DST https://stackoverflow.com/questions/13239534/accounting-for-dst-in-postgres-when-selecting-scheduled-items/13243029#13243029
- 在 Rails 和 PostgreSQL 中完全忽略时区 https://stackoverflow.com/questions/9571392/ignoring-time-zones-altogether-in-rails-and-postgresql/9576170#9576170