我有一个用户列表,需要根据他们的时区在每天的不同时间收到通知。
所以我基本上有2个表:Schedule和User
Schedule
-id
-scheduled_time
Users
-id
-schedule_id
-timezone
因此,可能会有9AM的时间表。 与此9AM时间表相关联的用户,他们的时区也设置为UTC -4或UTC -5。
我将提供一项服务,该服务每隔x分钟轮询一次以查询数据库。
这是我可以直接在PostgreSQL中执行的查询,还是该应用程序依赖于我使用的ORM?
答案 0 :(得分:0)
解析一天中的时间戳听起来很烦人,我建议您从Rails模型中进行解析。
如果您对从数据库中执行此操作一无所知,请参见以下问题:Convert a UTC timezone in postgresql to EST (local time),这是另一篇文章,描述了如何使用Postgres中的时区:http://blog.untrod.com/2016/08/actually-understanding-timezones-in-postgresql.html。
但是我的感觉是,如果使用ActiveSupport :: TimeWithZone数学,以便将每个用户与给定通知他们的给定UTC时间相关联,您将获得一个更简单,更轻松的解决方案。
示例:
时间表X在世界标准时间16:00运行,时间表Y在世界标准时间17:00运行。
用户A在UTC-0700(PDT)中,用户B在UTC-0600(山地)中。
如果B希望在上午10:00收到通知,请在您的应用程序中进行数学运算,以便将它们与Schedule X关联。 如果A希望在10:00 AM收到通知,请在您的应用程序中进行数学运算,以便将它们与计划Y关联。
让我知道您是否需要帮助。提示:
答案 1 :(得分:0)
我将提供一项服务,该服务每隔x分钟轮询一次以查询数据库。
这是我可以直接在Postgresql中执行的查询吗??
是的,可以。想象使用PostgreSQL服务器时间(函数now()
或current_timestamp
)为
SELECT u.*
FROM schedule s INNER JOIN users u
ON u.schedule_id=s.id
WHERE now()::time=(s.scheduled_time+u.timezone)
但是,正如我们将看到的,“每x分钟” 无法与Schedule表同步。有两种同步方式:
使用<=
并用布尔值的日标记更新用户表(每天24小时后进行清理以重新计划)。没有风险。
将=
与round(time,x) here一起使用...当您的“每x分钟” 假设不完善时,风险可能很小。
让我们模拟所有事情:
CREATE TABLE schedule (id serial PRIMARY KEY, scheduled_time time);
INSERT INTO schedule (scheduled_time) VALUES
(now()), ('9:00AM'::time), ('16:30'::time);
CREATE TABLE users (
id serial,
schedule_id int references schedule(id),
timezone interval -- see pg_timezone_names.utc_offset
);
INSERT INTO users (schedule_id,timezone) VALUES
(2, '00:00:00'::interval), (2, '-04:00:00'::interval), (1, '-05:00:00'::interval),
(1, '-05:00:00'::interval), (1, '-04:00:00'::interval), (2, '-05:00:00'::interval);
CREATE VIEW vw_user_scheduled AS
SELECT u.*, s.scheduled_time, s.scheduled_time+u.timezone AS ref_time
FROM schedule s INNER JOIN users u
ON u.schedule_id=s.id
;
示例vw_user_scheduled
是:
id | schedule_id | timezone | scheduled_time | ref_time
----+-------------+-----------+-----------------+-----------------
1 | 2 | 00:00:00 | 09:00:00 | 09:00:00
2 | 2 | -04:00:00 | 09:00:00 | 05:00:00
3 | 1 | -05:00:00 | 20:54:27.898109 | 15:54:27.898109
4 | 1 | -05:00:00 | 20:54:27.898109 | 15:54:27.898109
5 | 1 | -04:00:00 | 20:54:27.898109 | 16:54:27.898109
6 | 2 | -05:00:00 | 09:00:00 | 04:00:00
假设您采用舍入解决方案和x=5
(将每5分钟轮询一次以查询数据库的服务),则schedule_time 9AM(服务器时间)的用户将不是集合{id = 1,id = {2}和id = 6}(如scheduled_time
列所示,但只有用户id = 1正确的ref_time。
SELECT * from vw_user_scheduled
WHERE round_minutes(ref_time,5)=round_minutes(now(),5)
cited round time适用于时间数据类型。
CREATE FUNCTION round_minutes(time, integer) RETURNS time AS $$
SELECT
date_trunc('hour', $1)::time
+ (cast(($2::varchar||' min') as interval)
* round(
(date_part('minute',$1)::float + date_part('second',$1)/ 60.)::float
/ $2::float
))
$$ LANGUAGE SQL IMMUTABLE STRICT;
PS:由于问题不显示您的SQL表,因此有很多方法可以在表上模拟时间和时区格式。