Saf ve bilinçli datetime.now () <= challenge.datetime_end karşılaştırılamıyor


169

Karşılaştırma operatörlerini kullanarak modellerde belirtilen tarih ve saatlerle geçerli tarih ve saati karşılaştırmaya çalışıyorum:

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

Komut dosyası aşağıdaki hatalarla gider:

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

Modeller şuna benzer:

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

Ayrıca yerel tarih ve saatleri kullanan django'm var.

Bulamadığım şey, django'nun DateTimeField () için kullandığı format. Saf mı yoksa farkında mı? Ve yerel tarih saatini tanımak için datetime.now () öğesini nasıl alabilirim?




1
tarihle oynamak için çok güzel bir kitaplık var: sarkaç (ben bağlı değilim)
Thomas Decaux

Yanıtlar:


158

Varsayılan olarak, datetimenesne naivePython'dadır, bu nedenle ikisini de naif veya bilinçli datetimenesneler yapmanız gerekir . Bu, şu şekilde yapılabilir:

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

Not: Bu , zaten ayarlanmış bir ValueErrorif tzinfodeğerini yükseltecektir . Bundan emin değilseniz, sadece

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

BTW, aşağıdaki gibi saat dilimi bilgisiyle datetime.datetime nesnesinde bir UNIX zaman damgasını biçimlendirebilirsiniz

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)

Diyor ki: ValueError: Hesaplamaya çalıştığında naif tarihsaat değil (tzinfo zaten ayarlanmış): datetimeStart = utc.localize (challenge.datetime_start)
sccrthlt

evet, ValueError'ı yükseltir.
Dmitrii Mikhailov

4
Öğesini değiştirmek tzinfoherhangi bir dönüştürme yapmaz ve karşılaştırmayı yanlış yapar.
OrangeDog

Bunun için +1. Ve utc = pytz.utcpylint hatasını önlemek için kullanarak No value for argument 'dt' in unbound method call (no-value-for-parameter). pytz bağlantısı
sam

100

datetime.datetime.now saat dilimi farkında değil.

Django bunun için bir yardımcı ile birlikte gelir ve pytz

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

Karşılaştırmak gerekir nowiçinchallenge.datetime_start


3
Daha USE_TZ=Truesonra kurulmamış olsa timezone.now()bile saat dilimini tanıyan bir tarih saat nesnesi döndürürse pytz(ancak başka nedenlerle yüklenmesi önerilebilir).
jfs

58

Bir satır kod çözümü

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

Açıklanmış versiyon

# 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

Özet

Saat dilimi bilgilerini now()tarih saatinize eklemelisiniz .
Ancak, referans değişkenle aynı saat dilimini eklemeniz gerekir ; bu yüzden ilk önce tzinfoniteliği okudum .


21

Saat dilimini devre dışı bırakın. Kullanımchallenge.datetime_start.replace(tzinfo=None);

replace(tzinfo=None)Diğer tarihler için de kullanabilirsiniz .

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

2

Yani bu sorunu çözme şeklim, iki veri zamanının doğru zaman diliminde olmasını sağlamaktır.

datetime.now()Herhangi bir tzinfo seti olmadan, sistemlerin şimdiki zamanını döndürecek olanı kullandığınızı görebiliyorum .

tzinfo, hangi saat diliminde olduğunu bildirmek için bir tarih saatine eklenen bilgidir. Eğer saf datetime kullanıyorsanız, sisteminizde tutarlı olmanız gerekir. Sadece kullanmanızı şiddetle tavsiye ederimdatetime.utcnow()

tzinfo ile ilişkilendirilmiş tarih-saat yarattığınız bir yerde, yapmanız gereken bunların doğru zaman dilimine yerelleştirildiğinden (tzinfo ile ilişkilendirildiğinden) emin olmaktır.

Delorean'a bir bakın, bu tür şeylerle uğraşmayı çok daha kolay hale getiriyor.


9
Bu sorunu utcnow'da da görüyorsunuz.
Andy Hayden


0

Benden çalışıyor. Burada datetime oluşturulan tabloyu görüyorum ve datetime üzerine 10 dakika ekliyorum. daha sonra mevcut saate bağlı olarak, Vade İşlemleri yapılır.

from datetime import datetime, time, timedelta
import pytz

Veritabanı tarih saatine 10 dakika eklendi

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

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

Benim için çalıştı.


0

Sadece:

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

Öyleyse şunu yapın:

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

ve sonra kullan start_timeveend_time


0

Zaten bir saat dilimi olan date_time için saat dilimini ayarlamaya çalışıyorsunuz. Kullanım replaceve astimezoneişlevler.

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

current_time = datetime.now().replace(tzinfo=pytz.utc).astimezone(local_tz)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.