关于python:无法比较naive和aware datetime.now()>=challenge.datetime_end

Can't compare naive and aware datetime.now() <= challenge.datetime_end

我尝试使用比较运算符将当前日期和时间与模型中指定的日期和时间进行比较:

1
if challenge.datetime_start <= datetime.now() <= challenge.datetime_end:

脚本错误如下:

1
TypeError: can't compare offset-naive and offset-aware datetimes

模型如下:

1
2
3
4
class Fundraising_Challenge(models.Model):
    name = models.CharField(max_length=100)
    datetime_start = models.DateTimeField()
    datetime_end = models.DateTimeField()

我还让Django使用地区日期和时间。

我找不到Django用于DateTimeField()的格式。它是幼稚的还是有意识的?如何获取datetime.now()来识别区域设置datetime?


默认情况下,在python中,datetime对象是naive对象,因此您需要使这两个对象都是幼稚的或有意识的datetime对象。这可以通过以下方式实现:

1
2
3
4
5
6
7
8
import datetime
import pytz

utc=pytz.UTC

challenge.datetime_start = utc.localize(challenge.datetime_start)
challenge.datetime_end = utc.localize(challenge.datetime_end)
# now both the datetime objects are aware, and you can compare them

注:如果tzinfo已经设置,这将提高ValueError。如果你不确定,就用

1
2
start_time = challenge.datetime_start.replace(tzinfo=utc)
end_time = challenge.datetime_end.replace(tzinfo=utc)

顺便说一句,您可以用以下时区信息在datetime.datetime对象中格式化一个unix时间戳

1
2
3
4
5
6
7
8
9
d = datetime.datetime.utcfromtimestamp(int(unix_timestamp))
d_with_tz = datetime.datetime(
    year=d.year,
    month=d.month,
    day=d.day,
    hour=d.hour,
    minute=d.minute,
    second=d.second,
    tzinfo=pytz.UTC)


datetime.datetime.now不知道时区。

Django带了一个助手,这需要pytz

1
2
from django.utils import timezone
now = timezone.now()

您应该能够比较nowchallenge.datetime_start


一行代码解决方案

1
2
if timezone_aware_var <= datetime.datetime.now(timezone_aware_var.tzinfo):
    pass #some code

解释版本:

1
2
3
4
5
6
7
8
9
# Timezone info of your timezone aware variable
timezone = your_timezone_aware_variable.tzinfo

# Current datetime for the timezone of your variable
now_in_timezone = datetime.datetime.now(timezone)

# Now you can do a fair comparison, both datetime variables have the same time zone
if your_timezone_aware_variable <= now_in_timezone:
    pass #some code

总结:您必须将时区信息添加到您的now()日期时间中。但是,您必须添加引用变量的相同时区;这就是为什么我首先读取tzinfo属性的原因。


禁用时区。使用challenge.datetime_start.replace(tzinfo=None);

您还可以将replace(tzinfo=None)用于其他日期时间。

1
if challenge.datetime_start.replace(tzinfo=None) <= datetime.now().replace(tzinfo=None) <= challenge.datetime_end.replace(tzinfo=None):

所以我解决这个问题的方法是确保两个日期时间在正确的时区。

我可以看到您使用的是datetime.now(),它将返回系统当前时间,而不设置tzinfo。

TZINFO是附加到日期时间的信息,用于让它知道它在哪个时区。如果您使用的是naive datetime,那么您需要在整个系统中保持一致。我强烈建议只使用datetime.utcnow()

将要创建的日期时间视为与TZINFO相关联的日期时间,您需要做的是确保这些日期时间已本地化(与TZINFO相关联)到正确的时区。

看看德洛伦,它让处理这类事情变得容易多了。