Determining whether a UTC timestamp is within a time range in a timezone?
让我们将此问题构建为调度应用程序。 用户在其时区("America / New_York"中的"8am")指定最小时间,之后他们愿意接受约会。 (我们对最长时间也有类似的约束)
给定传入的约会请求(例如,对于UTC时间中的2016-09-07 03:00:00),我们需要确定哪些用户可以进行约会。
我们如何确定UTC时间戳是否在两个时区调整时间之间?
我的方法是将传入时间戳转换为用户的时区,提取时间部分并将其与时间约束进行比较:
1 2 3
| SELECT * FROM users u WHERE
('2016-09-07 03:00:00' AT TIME ZONE u.timezone)::TIME >= u.earliest_start_time AND
('2016-09-07 03:00:00' AT TIME ZONE u.timezone)::TIME <= u.latest_stop_time |
(earliest_start_time和latest_stop_time的类型为time without time zone; timezone是一个Olson tz字符串)
有各种奇怪的行为,因为时区偏移会导致数天翻身,而我通常对此非常困惑和朦胧。
-
您不一定,因为本地时间戳可能不明确。例如,假设您的用户为您提供了一个本地范围,结束于2016-11-06T01:30纽约时间。现在,是2016-11-05T21:45之前还是之后?它是在11月6日凌晨1:30在纽约首次发生之后,但是在第二次发生在凌晨1:30之前......基本上,你需要知道用户给出的"凌晨1:30"是第一次还是第二次发生...并应对其他情况,用户在凌晨1:30说但跳过了...
-
earliest_start_time和latest_stop_time的类型是什么?它是否包含日期信息,还是只是一天中的某个时间?
-
啊。我想我明白。鉴于我有一个最小和最大约束,我必须以某种方式在查询中编码假设我的意思是整个夜晚的范围?
-
@redneb只是时间。更新了问题。
-
这些预约开始时间是针对特定日期,还是(或多或少,t.b.d)定期,例如每个工作日从9到5或周三在4到6之间?如果是后者,那么你不应该只比较时间,而是完整的日期;因此,为此日期和开始/停止时间创建UTC时间戳(将用户时区考虑在内),然后根据该时间进行比较。
-
@CBroe它是前者;收到的日期都是一次性的,不是常规的。
为了使下面的代码更具可读性,假设占位符$1包含类型timestamp with time zone的值。 然后,以下查询将查找当时可用的所有用户:
1 2 3 4 5
| SELECT * FROM users u WHERE
$1 BETWEEN
($1::DATE || ' ' || u.earliest_start_time)::TIMESTAMP WITHOUT TIME zone AT TIME ZONE u.timezone
AND
($1::DATE || ' ' || u.latest_stop_time)::TIMESTAMP WITHOUT TIME zone AT TIME ZONE u.timezone; |
说明:我们取$1这是一个timestamp with time zone,我们只保留日期部分,按类型将其转换为date。 然后我们取earliest_start_time这是一个时间并将其与前一个日期相结合,我们得到没有时区信息的全时戳(尚未)。 然后我们指定将其转换为timestamp with time zone的时区。 我们对latest_stop_time做同样的事情。 现在我们已经找到了这两个timestamp with time zone值,我们可以将它们与具有相同类型的$1进行比较。
这会产生模糊时间戳的问题(即从DST到标准时间的过渡),但你无法避免这种情况。 如果您只在典型的营业时间使用它,那可能没问题。