对于一家商店,我希望该商店的商店开门和关门时间是当地时间。例:
Shop1 于当地时间 8:00 (t1( 开盘,并于当地时间 16:00 (t2( 关闭。Shop1 位于欧洲/伦敦 (tz(。
Shop2 当地时间 8:00 开门,当地时间 16:00 关门。Shop2 位于欧洲/哥本哈根。
问题:如何在给定时间选择营业的商店?我需要考虑 DST:在夏季的这个示例中,
Shop1 的营业时间为 08:00+01:00,Shop2 的营业时间为 08:00+02:00,而在冬季,Shop1 的营业时间为 08:00+00:00,Shop2 的营业时间为 08:00+01:00。将从具有许多行的表中进行选择,因此我需要对此进行索引。
使用 Django + PostgreSQL。
很酷的问题。 继续上面的Andomar的回答,假设您正在处理具有"意外"夏令时日期范围的几个时区,一种选择是:
-
将时区保存在
CharField
中,并在TimeField
中opens
和closes
:class Shop(models.Model): tz = models.CharField(max_length=200) opens = models.TimeField() closes = models.TimeField() Shop.objects.create(opens="8:00", closes="19:00", tz="Europe/Moscow") Shop.objects.create(opens="8:00", closes="19:00", tz="Europe/Berlin") Shop.objects.create(opens="8:00", closes="19:00", tz="UTC") Shop.objects.create(opens="8:00", closes="19:00", tz="Asia/Jerusalem") Shop.objects.create(opens="8:00", closes="19:00", tz="Europe/London") Shop.objects.create(opens="8:00", closes="19:00", tz="Europe/Copenhagen")
-
将"现在"计算为 UTC:
now_utc = "10:30"
-
使用 RawSQL 批注和筛选查询集:
qs = Shop.objects.annotate(is_open=RawSQL("(%s::time at time zone tz)::time between opens and closes", (now_utc,))).filter(is_open=True)
另一种解决方案是查询每个时区的数据库:
# pseudocode
for tz in all_timezones:
now_local = convert_to_timezone(now, tz) # beware - this might fail when DST is currently changing!
shops = Shop.objects.filter(tz=tz, opens__lte=now_local, closes__gte=now_local)
如果index_together
字段(tz
、opens
、closes
(,查询应利用索引。 但是,这并不意味着您的查询会更快。
请记住,您必须将午夜周围的营业时间保留在两个记录
Postgres支持使用at time zone
语法将时间转换为本地时间。 例如,要查找新西兰的当前时间:
select (current_timestamp at time zone 'NZDT')::time;
您可以使用它来选择在 10:00 营业的商店:
where ('10:00'::time at time zone time_zone)::time
between opens and closes
其中time_zone
是商店的时区,opens
商店的营业时间,closes
关闭时间。 regtester.com 的完整示例。