Django 开放时间与 UTC Support/Timezone 问题

Django Opening Hours With UTC Support/Timezone Issue

我有一个 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"

过程是这样的 - 这些时间由最终用户以表格形式输入,因此假定为本地时间,我的应用程序中使用的大多数 datetimes/times 都是 UTC 时间。我最初需要经常比较这两者,我想我可以找出每个位置对象的时区,然后每当我将某些东西与这些 OpeningHours 进行比较时,我可以只使用给定的时间和 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 package) and store that in the Location object (using a TimeZoneField)。也就是说,据我所知,它不会自动更新 DST 或类似的东西。每次我调用上面的函数时我都能弄清楚时区,但是我调用了很多这样的函数,这样在资源方面我想说这是边界线而不是一个选项。

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

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

你做对了。

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

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

  • 您可能希望仅在 locationweekeday 上使 LocationHours 唯一,除非您故意尝试允许同一地点有多个营业时间在同一个工作日。

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