无法比较天真和有意识的 datetime.now() <= challenge.datetime_end

问题描述 投票:0回答:15

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

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

脚本错误:

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

模型看起来像这样:

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

我还有 django 使用区域设置日期和时间。

我没能找到 django 用于 DateTimeField() 的格式。是天真还是有意识?如何让 datetime.now() 识别区域设置日期时间?

python django datetime comparison
15个回答
312
投票

默认情况下,Python 中的

datetime
对象是
naive
,因此您需要将它们都设置为 naive 或 aware
datetime
对象。这可以使用以下方法完成:

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

注意:如果

ValueError
已经设置,这将引发
tzinfo
。如果您对此不确定,请使用

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

顺便说一句,您可以在 datetime.datetime 对象中使用时区信息格式化 UNIX 时间戳,如下所示

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)

170
投票

datetime.datetime.now
不支持时区。

Django 为此提供了一个助手,这需要

pytz

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

您应该能够将

now
challenge.datetime_start

进行比较

136
投票

一行代码解决方案

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

解释版

# 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()
日期时间。
但是,您必须添加引用变量的same时区;这就是为什么我首先阅读
tzinfo
属性。


57
投票

禁用时区。 使用

challenge.datetime_start.replace(tzinfo=None);

您还可以使用

replace(tzinfo=None)
表示其他 日期时间

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

15
投票

没有第三方,只有本机日期时间模块。

from datetime import datetime, timedelta, timezone

time1 = datetime.strptime('2021-07-15T00:22:02+0000', '%Y-%m-%dT%H:%M:%S%z')
time2 = datetime(2021, 7, 15, tzinfo=timezone(offset=timedelta()))
if time1 < time2:
    print(True)

8
投票

要让您的日期时间对象时区不再天真,只需添加以下函数:

datetimeObject.astimezone()

4
投票

它对我有用。 在这里,我获取表创建的日期时间并在日期时间上添加 10 分钟。 稍后根据当前时间,到期操作完成。

from datetime import datetime, time, timedelta
import pytz

在数据库日期时间上添加了 10 分钟

table_datetime = '2019-06-13 07:49:02.832969'(示例)

# Added 10 minutes on database datetime
# table_datetime = '2019-06-13 07:49:02.832969' (example)

table_expire_datetime = table_datetime + timedelta(minutes=10 )

# Current datetime
current_datetime = datetime.now()


# replace the timezone in both time
expired_on = table_expire_datetime.replace(tzinfo=utc)
checked_on = current_datetime.replace(tzinfo=utc)


if expired_on < checked_on:
    print("Time Crossed)
else:
    print("Time not crossed ")

它对我有用。


2
投票

您正在尝试为已有时区的 date_time 设置时区。 使用

replace
astimezone
函数。

local_tz = pytz.timezone('Asia/Kolkata')

current_time = datetime.now().replace(tzinfo=pytz.utc).astimezone(local_tz)

1
投票

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

我可以看到您正在使用

datetime.now()
它将返回系统当前时间,没有设置 tzinfo。

tzinfo 是附加到日期时间的信息,让它知道它所在的时区。如果您使用简单的日期时间,则需要在整个系统中保持一致。我强烈建议只使用

datetime.utcnow()

看到您正在创建与 tzinfo 关联的日期时间,您需要做的是确保它们本地化(与 tzinfo 关联)到正确的时区。

看看Delorean,它使处理此类事情变得更加容易。


1
投票

如果您使用

SQLAlchemy
并存储 DateTime,那么您可以将其与时区信息一起存储。这将允许您将该日期时间与时区感知的日期时间进行比较。示例
SQLAlchemy core
中的列定义:

Column("created_at", DateTime(timezone=True), nullable=False)

1
投票

如果您使用的是 Python 3.6 及更高版本,则可以利用本机

datetime
功能。

utc_date = datetime.datetime.fromtimestamp(0, datetime.timezone.utc)

0
投票

在我的例子中,我已经使用 pytz 控制了时区,并且我已将日期转换为来自 django.utils 的本地时区:

import pytz
from django.utils import timezone

def _my_method(native_date, timezone):
    aware_date = datetime.now(pytz.timezone(timezone))
    return timezone.make_naive(aware_date) >  native_date

您还可以使用 timezone.make_aware 来了解本地日期


0
投票

我的笔记本中时不时会出现此错误...我不知道为什么。

我的日期时间对象通常位于数组中。我尝试了上面的一些答案,但我发现处理这个问题的方法是

import numpy as np
import matplotlib.dates as mdates

array_with_datetime = np.array( 
                          mdates.num2date( 
                                     mdates.date2num( 
                                                 array_with_datetime)))

不优雅,但有效。如果我不使用

np.array
,它会返回一个列表。


0
投票

[选项 1] 让两个对象

datetime
都意识到

示例代码:

from datetime import datetime, timezone
# If `challenge_datetime_end` is already timezone-aware, ensure `now()` is also aware
now_aware = datetime.now(timezone.utc)

# Now you can safely compare `now_aware` with `challenge_datetime_end`
if now_aware < challenge_datetime_end:
   # Your logic here

[选项 2] 使两个对象

datetime
天真

示例代码:

from datetime import datetime, timezone
# Assuming `challenge_datetime_end` is timezone-aware
challenge_datetime_end_naive = challenge_datetime_end.replace(tzinfo=None)
    
# Now you can compare it with the naive `datetime.now()`
if datetime.now() < challenge_datetime_end_naive:
# Your logic here

-2
投票

只是:

dt = datetimeObject.strftime(format) # format = your datetime format ex) '%Y %d %m'
dt = datetime.datetime.strptime(dt,format)

所以这样做:

start_time = challenge.datetime_start.strftime('%Y %d %m %H %M %S')
start_time = datetime.datetime.strptime(start_time,'%Y %d %m %H %M %S')

end_time = challenge.datetime_end.strftime('%Y %d %m %H %M %S')
end_time = datetime.datetime.strptime(end_time,'%Y %d %m %H %M %S')

然后使用

start_time
end_time

© www.soinside.com 2019 - 2024. All rights reserved.