我正在撰写“此时向我发送消息”应用。我以这种方式存储重复信息:
Schedules
----------
days_of_week: [3, 4, 5]
hours_of_day: [8, 13, 22]
time_zone: "Pacific Time (US & Canada)"
在显示方面工作正常,但我需要写一个频繁的cron作业,抓住所有“现在(utc)”的时间表。因此,如果cron作业在星期一09:00 UTC运行,我需要抓住所有的时间表
where days_of_week @> ARRAY[1]
)hours_of_day
的时间是UTC时间09:00。给定hours_of_day
存储为整数数组,但我们也存储用户的time_zone。因此,用户可能会说:“在星期一上午9点向我发送消息”(我们将其存储为[9]),但这意味着上午9点在他们的时区。
问题:
提前致谢!
答案 0 :(得分:3)
Postgres拥有使用时区的一流设施,我使用AT TIME ZONE构造编写了与您在此处所提出的内容非常相似的内容。除了你的字段之外,我还使用last_scheduled_at
来标记最后一次“执行”时间表 - 即,当最后一个成功的cron作业运行该时间表以避免双重调度时,以及{{1}用于逻辑删除计划。
我的日程表架构类似,只是我只有一个小时。我和你一样在数组中存储了几天,时区为deleted_at
。我的text
表格中的字段为schedules
,dows
和hour
。
这是查询:
timezone
我使用SELECT
s.*
FROM
schedules s
WHERE
ARRAY[extract(dow from timestamptz (now() at time zone timezone))] && dows
AND hour = extract(hour from timestamptz (now() at time zone timezone))
AND (s.last_scheduled_at IS NULL
OR s.last_scheduled_at < (now() - interval '12 hours'))
AND s.deleted_at IS NULL
LIMIT
1000
(重叠)而不是&&
(包含),但都可以使用。您可能还需要限制,以便您可以批量处理工作(继续运行此操作,如果结果为零,则完成X小时;确保在小时结束前完成工作)。您也可能希望将时间戳作为参数传递给此查询 - 我在此将其简化为@>
以简化操作,但将时间作为参数传递会使测试变得更加容易。
另请注意,Postgres可能会挑剔时区名称和缩写,其夏令时的行为可能违反直觉:例如,太平洋标准时间和太平洋夏令时被视为两个不同的时区(为了{{ 1}}):
now()
也就是说,无论您当前是否观察,夏令时始终存在。如果你让人们直接进入时区,最好拒绝这些或者自动将这些强制转换为'America / Los_Angeles'(或他们碰巧映射到的任何时区),这将根据你自动处理这些转换。您的Postgres版本具有的时区规则(如果对于频繁更改时区的区域,如果准确性至关重要,请确保及时更新到点发布)。 Postgres使用的时区名称列表可以在Olson database中找到。 Postgres表pg_timezone_names 并且pg_timezone_abbrevs也可能是有意义的。