Postgres:查询日程,给定日期,time_of_day和时区名称

时间:2015-10-10 05:30:40

标签: postgresql

我正在撰写“此时向我发送消息”应用。我以这种方式存储重复信息:

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运行,我需要抓住所有的时间表

  • 星期一是在days_of_week(where days_of_week @> ARRAY[1]
  • hours_of_day的时间是UTC时间09:00。给定hours_of_day存储为整数数组,但我们也存储用户的time_zone。

因此,用户可能会说:“在星期一上午9点​​向我发送消息”(我们将其存储为[9]),但这意味着上午9点在他们的时区。

问题:

  • 在给定这些参数的情况下查询所有计划的任何方法?
  • 如果没有,是否有更好的方法来构建数据以确保通过Postgres更容易查询?架构很灵活。

提前致谢!

1 个答案:

答案 0 :(得分:3)

Postgres拥有使用时区的一流设施,我使用AT TIME ZONE构造编写了与您在此处所提出的内容非常相似的内容。除了你的字段之外,我还使用last_scheduled_at来标记最后一次“执行”时间表 - 即,当最后一个成功的cron作业运行该时间表以避免双重调度时,以及{{1}用于逻辑删除计划。

我的日程表架构类似,只是我只有一个小时。我和你一样在数组中存储了几天,时区为deleted_at。我的text表格中的字段为schedulesdowshour

这是查询:

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也可能是有意义的。