关于postgresql:确定UTC时间戳是否在时区的时间范围内?

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_timelatest_stop_time的类型为time without time zone; timezone是一个Olson tz字符串)

有各种奇怪的行为,因为时区偏移会导致数天翻身,而我通常对此非常困惑和朦胧。


为了使下面的代码更具可读性,假设占位符$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到标准时间的过渡),但你无法避免这种情况。 如果您只在典型的营业时间使用它,那可能没问题。