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

Posted

技术标签:

【中文标题】无法比较天真和有意识的 datetime.now() <= challenge.datetime_end【英文标题】:Can't compare naive and aware datetime.now() <= challenge.datetime_end 【发布时间】:2013-02-24 19:14:45 【问题描述】:

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

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() 识别语言环境日期时间?

【问题讨论】:

***.com/questions/10652819/… Can't subtract offset-naive and offset-aware datetimes的可能重复 有一个非常不错的库可以用来玩日期:pendulum(我不隶属) 【参考方案1】:

默认情况下,datetime 对象在 Python 中是 naive,因此您需要将它们都设置为幼稚或有意识的 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

注意:如果 tzinfo 已设置,这将引发 ValueError。如果您不确定,请使用

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)

【讨论】:

它说:ValueError: Not naive datetime (tzinfo is already set) 当它试图计算时:datetimeStart = utc.localize(challenge.datetime_start) 是的,它引发了 ValueError。 替换tzinfo不做任何转换,导致比较不正确。 为此 +1。并且,使用utc = pytz.utc 来防止pylint 错误No value for argument 'dt' in unbound method call (no-value-for-parameter)。 pytz link 你可以从datetimetimezone模块获取utc时区。 timezone.utc.【参考方案2】:

datetime.datetime.now 不支持时区。

Django为此自带了一个helper,需要pytz

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

您应该能够比较 nowchallenge.datetime_start

【讨论】:

如果USE_TZ=Truetimezone.now() 会返回一个时区感知的日期时间对象,即使pytz 未安装(尽管可能出于其他原因建议安装)。【参考方案3】:

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

我可以看到您正在使用datetime.now(),它将返回系统当前时间,没有设置 tzinfo。

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

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

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

【讨论】:

您也可以在 utcnow 中看到这个问题。 第二。 utcnow 不会添加时区信息【参考方案4】:

一行代码解决方案

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() 日期时间。 但是,您必须添加参考变量的相同时区;这就是我第一次阅读tzinfo 属性的原因。

【讨论】:

这似乎是最合乎逻辑的方法 - 谢谢!【参考方案5】:

禁用时区。 使用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):

【讨论】:

【参考方案6】:

它对我有用。 在这里,我正在创建表创建日期时间并在日期时间上添加 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 ")

它对我有用。

【讨论】:

【参考方案7】:

只是:

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_timeend_time

【讨论】:

【参考方案8】:

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

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

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

【讨论】:

【参考方案9】:

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

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)

【讨论】:

你将如何使用 datetime.now() 完成这项工作? +many 不需要第三方库!!

以上是关于无法比较天真和有意识的 datetime.now() <= challenge.datetime_end的主要内容,如果未能解决你的问题,请参考以下文章

抑制 django 天真的日期时间警告

Django:查询时的天真日期时间

将 DateTime.Now 与 SQL Server 的开始时间和结束时间进行比较

django 比较 datetime.now 和 pub_date

比较 EF Core Linq 查询中的 DateTime

DateTime.Now 和文化/时区特定