pre_save 信号中 datetime.time() 比较的问题

Problem with datetime.time() comparison in a pre_save signal

我有那些型号:

class Interval(models.Model):
    from_time = models.TimeField(auto_now_add=False)
    to_time = models.TimeField(auto_now_add=False)

class CheckIn(models.Model):
    date_time = models.DateTimeField(auto_now_add=True)
    interval = models.ForeignKey(Interval, on_delete=models.SET_NULL)

主要目标是:

创建 CheckIn 时,代码应检查它是否在给定的时间间隔内。我需要比较这两个 return 它们在 %H:%M:%S 格式上的区别。

到目前为止我做了什么:

因为我有不同的场景如何处理给定的 CheckIn 在它被保存之前,我正在使用 pre_save 信号并且时间比较是这些场景的一部分。这是伪造的:

@receiver(pre_save, sender=CheckIn)
def set_action_state(sender, instance, **kwargs):
    if something:
       ...
       if another:
          ...
       else:
          ...
    else:
        # instance.date_time.time() is 13:56:56.568860 (2 hours behind, it should be 15 instead of 13)
        # instance.interval.from_time is 15:07:40
        if instance.date_time.time() < instance.interval.from_time:
            # this returns True when it's meant to return False

instance.date_time 是一个时区感知日期,因为我可以打印它是 tzinfo 其中 returns UTC 而不是 Europe/Sofia 作为我的 TIME_ZONE 在设置中,我不知道为什么。

所以我手动尝试通过以下方式将其设置为 tz

tz = pytz.timezone('Europe/Sofia')
dt1 = instance.date_time.replace(tzinfo=tz)
print(dt1.tzinfo) # which is the correct Europe/Sofia
print(dt1) # which is 13:56:56.568860, again 2 hours behind even with different timezone.

我尝试的第二件事是将 instance.interval.from_time 转换为感知日期时间,然后比较两个日期的 time()

def time_to_datetime(date, time):
    return make_aware(datetime.datetime.combine(date, time))

dt2 = time_to_datetime(dt1.date(), instance.interval.from_time)
print(dt2.tzinfo) #this returns 'Europe/Sofia'
print(dt2) #this is 15:07:40

现在 dt1dt2 都知道了,但仍然没有运气来比较它们。这是完整的代码:

tz = pytz.timezone('Europe/Sofia')
dt1 = instance.date_time.replace(tzinfo=tz)
dt2 = time_to_datetime(dt1.date(), instance.interval.from_time)
print(dt1.time() < dt2.time()) # this is True
print(dt1.tzinfo) # 'Europe/Sofia'
print(dt2.tzinfo) # 'Europe/Sofia'
print(dt1.time()) # 13:56:56.568860
print(dt1.time()) # 15:07:40

我怎样才能在 dt1 中获得正确的时间并且这种比较能够正常工作,即使两个日期时间都知道正确的时区?

编辑: 我的设置中有 USE_TZ = True

我做了一些谷歌搜索,发现 django 打算始终在模型中以 UTC 格式保存,但在从数据库检索期间转换为设置设置的 TIME_ZONE 格式。 link。所以我想在预保存实例中它有可能是 UTC 格式。我可能是错的,因为我对此没有具体的了解。

我认为这种比较需要实时进行。因此,现在使用用户 TIME_ZONE 与区间 from_time 进行比较是非常安全的。所以我的建议

import pytz
import datetime


tz = pytz.timezone('Europe/Sofia')
curtime = tz.localize(datetime.datetime.now())

并转换这行代码

  if instance.date_time.time() < instance.interval.from_time:
            # this returns True when it's meant to return False

   if curtime < instance.interval.from_time:
            # I hope this return False now

Django 不保证 Python 代码中日期时间的时区。这是因为 1) 时区主要与用户交互相关(这就是 activate() 影响表单和模板的原因)和 2) Python 比较操作是时区感知的,因此特定时区不会影响结果.

当然,一个不识别时区的操作是从日期时间中提取时间并将其与另一个时间进行比较。因此,您必须手动将日期时间转换为正确的时区。您的想法是正确的,但是 replace() 是错误的做法。 (不仅仅是转换到另一个时区,它改变实际时刻。)

相反,这样做:

from django.utils.timezone import localtime

if localtime(instance.date_time).time() < instance.interval.from_time:
    pass