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”这样的名称表示)不仅仅是一个偏移量,它是一组用于计算历史上任何一点的本地时间的规则。因此,无论您何时碰巧记录了时区名称,它都会做正确的事情。
关于您发布的代码的一些其他注释:
您可能希望仅在 location
和 weekeday
上使 LocationHours
唯一,除非您故意尝试允许同一地点有多个营业时间在同一个工作日。
您的 is_dt_within_location_hours()
相当低效。您不需要每次都获取所有 LocationHours
对象并重新计算工作日。相反,首先计算当地时间,然后过滤 location.hours
以仅包含该工作日的 LocationHours
个对象。
我有一个 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”这样的名称表示)不仅仅是一个偏移量,它是一组用于计算历史上任何一点的本地时间的规则。因此,无论您何时碰巧记录了时区名称,它都会做正确的事情。
关于您发布的代码的一些其他注释:
您可能希望仅在
location
和weekeday
上使LocationHours
唯一,除非您故意尝试允许同一地点有多个营业时间在同一个工作日。您的
is_dt_within_location_hours()
相当低效。您不需要每次都获取所有LocationHours
对象并重新计算工作日。相反,首先计算当地时间,然后过滤location.hours
以仅包含该工作日的LocationHours
个对象。