查询当地时间

时间:2017-02-14 16:09:52

标签: django postgresql timezone

对于一家商店,我希望在当地时间为该商店存储开放和关闭时间。示例:

Shop1在8.00(t1)开盘,当地时间16.00(t2)关闭。 Shop1位于Europe / London(tz)。

Shop2在8.00开门,当地时间16.00关闭。 Shop2位于欧洲/哥本哈根。

问题:我如何在特定时间选择开放的商店?我需要考虑夏令时:在夏天的这个例子中,Shop1的开放时间是08:00 + 01:00,Shop2的开放时间是08:00 + 02:00,而冬天,这将是08: Shop1为00 + 00:00,Shop2为00:00 + 01:00。

将从包含许多行的表中进行选择,因此我需要将其编入索引。

使用Django + PostgreSQL。

2 个答案:

答案 0 :(得分:1)

很酷的问题。继续Andomar's answer above,假设您正在使用"意外"处理几个时区。夏令时日期范围,一个选项将是:

  • 将时区保存在CharField,以及opens中的closesTimeField

    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字段(tzopenscloses),则查询应使用索引。但是,这并不意味着您的查询会更快。

请记住,您必须在两个记录中保持午夜的开放时间" 22:00" - " 00:00"和" 00:00" - " 03:00"而不是" 22:00" - " 03:00"。

答案 1 :(得分:0)

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关闭时间。 Full example at regtester.com.