例
Alfred and Lotta both live in Stockholm (+1 hour from UTC,but +2h
when it’s DST).
Sharon lives in Singapore (+8 hours from UTC,no
DST)During winter,Alfred sets an alarm for 4 AM. The alarm should go off
at 4 AM local time,all year.
During summer,Lotta sets an alarm
for 5 AM. Again,it should go off at 5 AM all year round.
Meanwhile,Sharon has set an alarm for 11 AM.All of these can be stored in the database as 03:00 UTC.
If I query the database in the winter for alarms that should go off at
03:00 UTC,I want Alfred’s and Sharon’s alarms. Singapore is now +7h
from Sweden,so 11 AM in Singapore is 4 AM in Sweden. Lotta’s alarm
should not go off for another hour.Conversely,if I query the database in the summer for alarms that
should go off at 03:00 UTC,I want Lotta’s and Sharon’s alarms.
Singapore is +6h from Sweden now,so 11 AM in Singapore is 5 AM in
Sweden now. Sven’s alarm went off an hour ago.
如果需要,我可以更改db模式.目前,我们根本不调整DST,实际上只有一个“小时”的整数字段(看起来很笨,时间域会更好).
看来我需要存储UTC时间和时区信息,但我不知道如何最好地在Postgres中实现这一点.我发现Postgres有一些时区的概念,但是我没有时区字段类型.此外,我想我需要在sql中进行一些计算,以确定如何根据时区数据和创建日期来偏移选择中的UTC时间.我对sql不是很好
我想在Postgres中解决这个问题,因为可能会有很多“警报”,我想避免将所有这些都提取到Ruby中并将其过滤掉的性能问题. (是的,这是一个Rails应用程序.)
解决方法
报警时间可以是[无时区].
但是您必须为每一行显式保存时区.
不要使用时区与时区这是一个逻辑破碎的类型,其使用不鼓励Postgresql. I quote the manual here:
The type time with time zone is defined by the sql standard,but the
definition exhibits properties which lead to questionable usefulness.
In most cases,a combination of date,time,timestamp without time
zone,and timestamp with time zone should provide a complete range of
date/time functionality required by any application.
演示设置:
CREATE TABLE alarm(name text,t time,tz text); INSERT INTO alarm VALUES ('Alfred','04:00','Europe/Stockholm') -- Alfred sets an alarm for 4 AM.,('Lotta','05:00','Europe/Stockholm') -- Lotta sets an alarm for 5 AM.,('Sharon','11:00','Asia/Singapore'); -- Sharon has set an alarm for 11 AM.
它必须是时区名称(而不是缩写)来解释DST.
考虑this related question的信息.
获取匹配的“today”警报:
SELECT * FROM alarm WHERE (('2012-07-01'::date + t) AT TIME ZONE tz AT TIME ZONE 'UTC')::time = '03:00'::time
>(‘2012-7-1’:: date t)…组合时间戳[没有时区]
也可以现在():: date t为“今天”.
> AT WITH TIME ZONE tz
…在保存的时区放置时间戳,导致timestamptz.
> AT WITH TIME ZONE’UTC’…获取UTC时间戳
> :: time …最简单的方法来提取时间组件.
这里可以查询time zone names:
SELECT * FROM pg_timezone_names WHERE name ~~* '%sing%' LIMIT 10
SQL Fiddle展示夏/冬.