带有 UTC 支持/时区问题的 Django 开放时间

Posted

技术标签:

【中文标题】带有 UTC 支持/时区问题的 Django 开放时间【英文标题】:Django Opening Hours With UTC Support/Timezone Issue 【发布时间】:2021-04-10 17:09:50 【问题描述】:

我有一个 Django 应用程序,用户可以在其中设置商店。我最近添加了支持开放时间的功能,遵循此线程上的建议 - Business Opening hours in Django。我的模型如下所示:

class LocationHours(SafeDeleteModel):
    location = models.ForeignKey(Location, related_name="hours", on_delete=models.CASCADE)

    weekday = models.IntegerField(choices=WEEKDAYS, blank=False, null=False)
    start_time = models.TimeField(blank=False, null=False, help_text="Opening time (00:00 format)")
    end_time = models.TimeField(blank=False, null=False, help_text="Closing time (00:00 format)")

    class Meta:
        ordering = ('weekday', 'start_time')
        unique_together = ('location', 'weekday', 'start_time', 'end_time')
        verbose_name_plural = "Location hours"

流程是这样的 - 这些时间由最终用户以表格形式输入,因此假定为本地时间,我的应用程序中使用的大多数日期时间/时间都是 UTC。我最初需要经常比较这两者,我想我可以找出每个位置对象的时区,然后每当我将某些东西与这些 OpenHours 进行比较时,我就可以使用给定的时间和 tz(在关联的 Location 对象上)计算 UTC 时间,然后它只是一个常规的日期时间比较。

我编写了以下函数来尝试解决这个问题:

def is_dt_within_location_hours(location, dt):
    # see if time falls within hours
    hours = location.hours
    if hours.count() > 0:
        for hour in hours.all():
            dt = dt.astimezone(hour.location.timezone)
            if dt.weekday() == hour.weekday:
                if hour.start_time < dt.time() < hour.end_time:
                    return True
        return False
    else:  # this location has no hours
        return True

我认为这可行,但有一些问题。

主要问题是 - 当最初制作或编辑 Location 对象时,我查找它所在的时区(使用 timezonefinder 包)并将其存储在 Location 对象中(使用 TimeZoneField)那时。也就是说,据我所知,它不会自动更新 DST 或类似的东西。每次调用上述函数时,我都可以计算出时区,但是我将所述函数调用了很多,因此从资源方面来说,我想说这不是一个选项。

我想我可以找到一种方法来找出本地时间在他们创建一个 OpeningHours 对象的那一刻,这样我就可以转换为 UTC 并保存它,但我不知道这样做的好方法。

我现在在想,我可能需要放弃我的整个解决方案并从头开始,但任何建议都非常有帮助,我已经为此苦苦挣扎了一段时间。

【问题讨论】:

【参考方案1】:

你做对了。

您担心在记录 Location 和进行计算之间时区偏移量会发生变化(与 DST 一样)。但是时区(由“美国/芝加哥”之类的名称表示)不仅仅是一个偏移量,它是一组用于计算历史上任何时间点的本地时间的规则。因此,无论您何时记录时区名称,它都会做正确的事情。

关于您发布的代码的其他一些注释:

您可能想让LocationHours 仅在locationweekeday 上独一无二,除非您故意尝试在同一工作日允许同一地点的多个营业时间。

您的is_dt_within_location_hours() 效率很低。您无需每次都获取所有 LocationHours 对象并重新计算工作日。相反,首先计算本地时间,然后过滤 location.hours 以仅包含该工作日的 LocationHours 对象。

【讨论】:

以上是关于带有 UTC 支持/时区问题的 Django 开放时间的主要内容,如果未能解决你的问题,请参考以下文章

查询 Django 模型时,如何将 Django 中的 DateTimeField 从 UTC 转换为最终用户的时区(通常是 PST)?

如何确保保存在数据库中的UTC日期等于Django中指定时区的午夜[重复]

Django 和时区

Django时区

Django时区

关于django的时区设置