【问题标题】:Postgres: query schedule given day, time_of_day, and time zone namePostgres:查询时间表给定日期、time_of_day 和时区名称
【发布时间】:2015-10-10 15:47:47
【问题描述】:

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

Schedules
----------
days_of_week: [3, 4, 5]
hours_of_day: [8, 13, 22]
time_zone: "Pacific Time (US & Canada)"

显示效果很好,但我需要编写一个频繁的 cron 作业来获取“现在(UTC)”的所有时间表。因此,如果 cron 作业在 UTC 星期一 09:00 运行,我需要获取所有日程安排,其中

  • 星期一是 days_of_week (where days_of_week @> ARRAY[1])
  • hours_of_day 是 09:00 UTC。这是因为hours_of_day 存储为整数数组,但我们也存储了用户的 time_zone。

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

问题:

  • 在给定这些参数的情况下,有什么方法可以查询所有计划?
  • 如果没有,是否有更好的方法来构建数据以确保更轻松地通过 Postgres 进行查询?架构很灵活。

提前致谢!

【问题讨论】:

  • 您的意思是在第 3 天 8 小时、4-13 小时和 5-22 小时发送消息,还是在第 3-4-5 天的所有 8-13-22 小时发送消息?

标签: postgresql


【解决方案1】:

Postgres 具有处理时区的一流设施,我使用AT TIME ZONE 构造编写了与您在此处询问的内容非常相似的内容。除了您的字段之外,我还使用last_scheduled_at 标记上次“执行”计划的时间 - 即,当最后一次成功的 cron 作业为该计划运行以避免双重计划时,以及 deleted_at 用于逻辑删除时间表。

除了我只有一个小时之外,我的日程安排模式相似。我像您一样将天数存储在一个数组中,并将时区存储为text。我的schedules 表中的字段是dowshourtimezone

这是查询:

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

我使用&amp;&amp;(重叠)而不是@&gt;(包含),但两者都可以。您可能还需要该限制,以便您可以分批处理工作(继续运行此程序,如果结果为零,您将在 X 小时内完成;确保在一小时结束前完成工作)。您可能还希望将时间戳作为参数传递给该查询——我在这里将其内联为 now() 以简化操作,但将时间作为参数传递会使测试变得容易得多。

另请注意,Postgres 可能对时区名称和缩写很挑剔,并且它在夏令时的行为可能违反直觉:例如,太平洋标准时间和太平洋夏令时间被视为两个不同的时区(出于 @987654336 的目的@):

maciek=# select now() at time zone 'pst';
          timezone          
----------------------------
 2015-10-09 23:14:51.856813
(1 row)

maciek=# select now() at time zone 'pdt';
          timezone          
----------------------------
 2015-10-10 00:14:54.402524
(1 row)

也就是说,夏令时始终存在,无论您是否正在观察它。如果您让人们直接进入时区,最好拒绝这些或自动将它们强制转换为“America/Los_Angeles”(或他们碰巧映射到的任何时区),它将根据您自动处理这些转换您的 Postgres 版本具有的时区规则(如果准确性对于时区频繁更改的区域至关重要,请确保及时更新到点发布)。 Postgres 使用的时区名称列表可以在Olson database 中找到。 Postgres 表pg_timezone_namespg_timezone_abbrevs 也可能感兴趣。

【讨论】:

  • 出色且详尽的答案。继续加油!
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-17
  • 2014-11-10
相关资源
最近更新 更多