Tidak dapat membandingkan naif dan sadar datetime.now () <= challenge.datetime_end

154

Saya mencoba membandingkan tanggal dan waktu saat ini dengan tanggal dan waktu yang ditentukan dalam model menggunakan operator perbandingan:

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

Kesalahan skrip dengan:

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

Modelnya terlihat seperti ini:

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

Saya juga punya Django menggunakan tanggal dan waktu lokal.

Yang belum bisa saya temukan adalah format yang digunakan Django untuk DateTimeField (). Apakah naif atau sadar? Dan bagaimana cara mendapatkan datetime.now () untuk mengenali datetime lokal?

sccrthlt
sumber
2
kemungkinan duplikat dari Tidak dapat mengurangi offset-naif dan data sadar-offset
PhoenixS
1
ada lib yang sangat bagus untuk bermain dengan tanggal: pendulum (saya tidak berafiliasi)
Thomas Decaux

Jawaban:

137

Secara default, datetimeobjek berada naivedalam Python, jadi Anda harus membuat keduanya objek yang naif atau sadar datetime. Ini dapat dilakukan dengan menggunakan:

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

Catatan: Ini akan menaikkan ValueErrorjika tzinfosudah diatur. Jika Anda tidak yakin tentang itu, gunakan saja

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

BTW, Anda bisa memformat stempel waktu UNIX di objek datetime.datetime dengan info zona waktu sebagai berikut

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)
Viren Rajput
sumber
Bunyinya: ValueError: Datetime tidak naif (tzinfo sudah ditetapkan) ketika mencoba menghitung: datetimeStart = utc.localize (challenge.datetime_start)
sccrthlt
ya, itu meningkatkan ValueError.
Dmitrii Mikhailov
4
Mengganti tzinfotidak melakukan konversi, membuat perbandingan salah.
OrangeDog
+1 untuk ini. Dan, gunakan utc = pytz.utcuntuk mencegah kesalahan pylint No value for argument 'dt' in unbound method call (no-value-for-parameter). tautan pytz
sam
90

datetime.datetime.now tidak sadar zona waktu.

Django datang dengan pembantu untuk ini, yang membutuhkan pytz

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

Anda harus dapat membandingkan nowkechallenge.datetime_start

Alfredo Aguirre
sumber
3
Jika USE_TZ=Truekemudian timezone.now()mengembalikan objek waktu-sadar zona waktu bahkan jika pytztidak diinstal (meskipun mungkin disarankan untuk menginstal karena alasan lain).
jfs
49

Satu baris solusi kode

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

Versi yang dijelaskan

# 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

Ringkasan

Anda harus menambahkan info zona waktu ke now()datetime Anda .
Namun, Anda harus menambahkan zona waktu yang sama dari variabel referensi; itu sebabnya saya pertama kali membaca tzinfoatribut.

ePi272314
sumber
18

Nonaktifkan zona waktu. Menggunakanchallenge.datetime_start.replace(tzinfo=None);

Anda juga dapat menggunakan replace(tzinfo=None)untuk datetime lainnya .

if challenge.datetime_start.replace(tzinfo=None) <= datetime.now().replace(tzinfo=None) <= challenge.datetime_end.replace(tzinfo=None):
Amin Fathi
sumber
2

Jadi cara saya akan memecahkan masalah ini adalah untuk memastikan dua datetimes berada di zona waktu yang tepat.

Saya dapat melihat bahwa Anda menggunakan datetime.now()yang akan mengembalikan waktu sistem saat ini, tanpa set tzinfo.

tzinfo adalah informasi yang dilampirkan pada datetime untuk memberi tahu zona waktu itu. Jika Anda menggunakan datetime naif, Anda harus konsisten melalui sistem Anda. Saya sangat merekomendasikan hanya menggunakandatetime.utcnow()

melihat di suatu tempat Anda sedang membuat datetime yang memiliki tzinfo terkait dengan mereka, apa yang perlu Anda lakukan adalah memastikan mereka dilokalkan (memiliki tzinfo terkait) ke zona waktu yang benar.

Lihatlah Delorean , itu membuat berurusan dengan hal semacam ini jauh lebih mudah.

myusuf3
sumber
8
Anda juga melihat masalah ini dengan utcnow.
Andy Hayden
0

Ini bekerja dari saya. Di sini saya membuat geeting tabel yang dibuat datetime dan menambahkan 10 menit pada datetime. nanti tergantung pada waktu saat ini, Operasi Kedaluwarsa selesai.

from datetime import datetime, time, timedelta
import pytz

Menambahkan 10 menit pada waktu database

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

# 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 ")

Ini berhasil untuk saya.

Chandan Sharma
sumber
0

Hanya:

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

Jadi lakukan ini:

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')

lalu gunakan start_timedanend_time

Harispy
sumber