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

时间:2019-01-18 15:22:38

标签: django python-3.x datetime django-models django-timezone

我有那些型号:

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时,代码应检查它是否在给定的时间间隔内。我需要比较两者,并以%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会返回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

2 个答案:

答案 0 :(得分:1)

对于Python代码中的日期时间所在的时区,Django不做任何保证。这是因为1)时区与用户交互最相关(这就是activate()影响表单和模板的原因),并且2)Python比较操作可识别时区,因此特定时区不会影响结果。

当然,一个不支持时区的操作是从日期时间中提取时间并将其与另一个时间进行比较。因此,您必须手动将日期时间转换为正确的时区。您的想法正确,但是replace()是错误的实现方式。 (而不是转换到另一个时区,它会更改实际时间。)

相反,请执行以下操作:

from django.utils.timezone import localtime

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

答案 1 :(得分:0)

我进行了一次谷歌搜索,发现django打算始终以UTC格式保存在模型中,但是在从db检索期间,将其转换为设置所设置的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