素朴で認識可能なdatetime.now()<= challenge.datetime_endを比較できません


153

現在の日付と時刻を、比較演算子を使用してモデルで指定された日付と時刻と比較しようとしています:

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()でロケールの日時を認識するにはどうすればよいですか?




1
日付で遊ぶには非常に素晴らしいlibがあります:振り子(私は提携していません)
Thomas Decaux

回答:


135

デフォルトでは、datetimeオブジェクトはnaivePythonであるため、両方とも単純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

注:これは、ValueErrorif 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)

それは言う:ValueError:計算しようとしたときに単純な日時(tzinfoは既に設定されています):datetimeStart = utc.localize(challenge.datetime_start)
sccrthlt

うん、それはValueErrorを発生させます。
ドミトリミハイロフ

4
を置き換えてtzinfoも変換は行われず、比較が不正確になります。
OrangeDog 2017年

+1。そして、utc = pytz.utcpylintエラーを防ぐために使用しますNo value for argument 'dt' in unbound method call (no-value-for-parameter)pytzリンク
sam

90

datetime.datetime.now タイムゾーンに対応していません。

Djangoにはこのためのヘルパーが付属しています。 pytz

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

あなたは比較nowすることができるはずですchallenge.datetime_start


3
もしUSE_TZ=True、その後timezone.now()場合でも、タイムゾーンを意識したDateTimeオブジェクトを返しますpytz(他の理由のためにインストールすることをお勧めかもしれませんが)インストールされていません。
jfs

49

1行のコードソリューション

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属性を読み取りました。


18

タイムゾーンを無効にします。使用する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):

2

したがって、この問題を解決する方法は、2つの日時が正しいタイムゾーンであることを確認することです。

datetime.now()tzinfoを設定せずに、システムの現在時刻を返すものを使用していることがわかります。

tzinfoは、それがどのタイムゾーンにあるかを知らせるために日時に付加される情報です。単純な日時を使用している場合は、システム全体で一貫している必要があります。のみを使用することを強くお勧めしますdatetime.utcnow()

tzinfoが関連付けられているdatetimeをどこかに作成しているように見えるので、必要なのは、それらが正しいタイムゾーンにローカライズされている(tzinfoが関連付けられている)ことを確認することです。

Deloreanを見てください。このようなことへの対応がはるかに簡単になります。


8
この問題はutcnowでも発生します。
アンディヘイデン

0

私の働きです。ここでは、作成された日時をテーブルに追加し、日時に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 ")

それは私のために働いた。


0

ただ:

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.