ไม่สามารถเปรียบเทียบ datetime.now ที่ไร้เดียงสาและรับทราบ () <= challenge.datetime_end


154

ฉันกำลังพยายามเปรียบเทียบวันที่และเวลาปัจจุบันกับวันที่และเวลาที่ระบุในแบบจำลองโดยใช้ตัวดำเนินการเปรียบเทียบ:

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 ที่ดีมากที่จะเล่นกับวันที่: ลูกตุ้ม (ฉันไม่ได้เป็นพันธมิตร)
โทมัส Decaux

คำตอบ:


137

โดยค่าเริ่มต้นdatetimeวัตถุนั้นอยู่naiveใน Python ดังนั้นคุณต้องทำให้ทั้งคู่เป็น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)

BTW คุณสามารถจัดรูปแบบเวลาประทับ UNIX ในวัตถุ datetime.datetime ด้วยข้อมูลเขตเวลาดังต่อไปนี้

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: ไม่ใช่ datetime ไร้เดียงสา (tzinfo ถูกตั้งค่าไว้แล้ว) เมื่อพยายามคำนวณ: datetimeStart = utc.localize (challenge.datetime_start)
sccrthlt

ใช่มันเพิ่ม ValueError
Dmitrii Mikhailov

4
การแทนที่การtzinfoไม่ทำการแปลงใด ๆ ทำให้การเปรียบเทียบไม่ถูกต้อง
OrangeDog

+1 สำหรับสิ่งนี้ และใช้เพื่อป้องกันไม่ให้เกิดข้อผิดพลาดutc = pytz.utc pylint ลิงก์ pytzNo value for argument 'dt' in unbound method call (no-value-for-parameter)
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

โซลูชันบรรทัดเดียว

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()datetime
อย่างไรก็ตามคุณต้องเพิ่มเขตเวลาเดียวกันของตัวแปรอ้างอิง นั่นคือเหตุผลที่ฉันอ่าน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

วิธีที่ฉันจะแก้ปัญหานี้คือเพื่อให้แน่ใจว่าชุดข้อมูลสองชุดอยู่ในเขตเวลาที่ถูกต้อง

ฉันเห็นว่าคุณกำลังใช้datetime.now()ซึ่งจะคืนค่าเวลาปัจจุบันของระบบโดยไม่มีการตั้งค่า tzinfo

tzinfo เป็นข้อมูลที่แนบมากับวันที่และเวลาเพื่อให้ทราบว่าเป็นเขตเวลาใดหากคุณใช้วันที่และเวลาที่ไร้เดียงสาคุณจะต้องมีความสอดคล้องกันตลอดทั้งระบบของคุณ ฉันอยากจะแนะนำให้ใช้เท่านั้นdatetime.utcnow()

เมื่อคุณเห็นว่าคุณกำลังสร้างวันที่และเวลาที่มี tzinfo เชื่อมโยงอยู่สิ่งที่คุณต้องทำคือตรวจสอบให้แน่ใจว่ามีการแปลเป็นภาษาท้องถิ่น (มีการเชื่อมโยง tzinfo) กับเขตเวลาที่ถูกต้อง

ลองดูที่Deloreanมันทำให้การจัดการกับเรื่องแบบนี้ง่ายขึ้นมาก


8
คุณจะเห็นปัญหานี้ด้วย utcnow
Andy Hayden

0

มันทำงานแบบฉัน ที่นี่ฉัน geeting ตารางสร้างวันที่และเวลาเพิ่ม 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_timeและend_time

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.