Không thể so sánh datetime ngây thơ và nhận thức.now () <= Challenge.datetime_end


153

Tôi đang cố gắng so sánh ngày và giờ hiện tại với ngày và giờ được chỉ định trong các mô hình bằng các toán tử so sánh:

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

Các kịch bản lỗi với:

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

Các mô hình trông như thế này:

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

Tôi cũng có django sử dụng ngày và thời gian địa phương.

Thứ tôi không thể tìm thấy là định dạng django sử dụng cho DateTimeField (). Là ngây thơ hay nhận thức? Và làm cách nào để tôi lấy datetime.now () để nhận ra datetime địa phương?




1
có một lib rất hay để chơi với ngày: con lắc (tôi không liên kết)
Thomas Decaux

Câu trả lời:


135

Theo mặc định, datetimeđối tượng nằm naivetrong Python, vì vậy bạn cần làm cho cả hai datetimeđối tượng ngây thơ hoặc nhận biết . Điều này có thể được thực hiện bằng cách sử dụng:

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

Lưu ý: Điều này sẽ tăng ValueErrornếu tzinfođã được đặt. Nếu bạn không chắc chắn về điều đó, chỉ cần sử dụng

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

BTW, bạn có thể định dạng dấu thời gian UNIX trong đối tượng datetime.datetime với thông tin múi giờ như sau

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)

Nó nói: ValueError: Không ngây thơ datetime (tzinfo đã được đặt) khi nó cố gắng tính toán: datetimeStart = utc.localize (Challenge.datetime_start)
sccrthlt

vâng, nó làm tăng ValueError.
Dmitrii Mikhailov

4
Thay thế tzinfokhông thực hiện bất kỳ chuyển đổi, làm cho so sánh không chính xác.
OrangeDog

+1 cho điều này. Và, sử dụng utc = pytz.utcđể ngăn ngừa lỗi pylint No value for argument 'dt' in unbound method call (no-value-for-parameter). liên kết pytz
sam

90

datetime.datetime.now không nhận thức được múi giờ.

Django đi kèm với một người trợ giúp cho việc này, đòi hỏi pytz

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

Bạn sẽ có thể so sánh nowvớichallenge.datetime_start


3
Nếu USE_TZ=Truesau đó timezone.now()trả về một đối tượng datetime nhận biết múi giờ ngay cả khi pytzkhông được cài đặt (mặc dù có thể nên cài đặt vì lý do khác).
JFS

49

Một dòng giải pháp mã

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

Phiên bản giải thích

# 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

Tóm lược

Bạn phải thêm thông tin múi giờ vào now()datetime của bạn .
Tuy nhiên, bạn phải thêm cùng múi giờ của biến tham chiếu; đó là lý do tại sao lần đầu tiên tôi đọc tzinfothuộc tính.


18

Vô hiệu hóa múi giờ. Sử dụngchallenge.datetime_start.replace(tzinfo=None);

Bạn cũng có thể sử dụng replace(tzinfo=None)cho datetime khác .

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

2

Vì vậy, cách tôi sẽ giải quyết vấn đề này là đảm bảo hai mốc thời gian ở đúng múi giờ.

Tôi có thể thấy rằng bạn đang sử dụng datetime.now()sẽ trả về thời gian hiện tại của hệ thống, không có bộ tzinfo.

tzinfo là thông tin được đính kèm với datetime để cho nó biết múi giờ đó là gì. Nếu bạn đang sử dụng datetime ngây thơ, bạn cần nhất quán trong toàn bộ hệ thống của mình. Tôi rất khuyên bạn chỉ nên sử dụngdatetime.utcnow()

nhìn thấy ở đâu đó bạn đang tạo datetime có tzinfo được liên kết với chúng, điều bạn cần làm là đảm bảo rằng chúng được bản địa hóa (có tzinfo được liên kết) với múi giờ chính xác.

Hãy nhìn vào Delorean , nó làm cho việc đối phó với loại điều này dễ dàng hơn nhiều.


8
Bạn cũng thấy vấn đề này với utcnow.
Andy Hayden

0

Đó là hình thức làm việc cho tôi. Ở đây tôi đang geeting bảng đã tạo datetime và thêm 10 phút vào datetime. sau đó tùy thuộc vào thời gian hiện tại, hoạt động hết hạn được thực hiện.

from datetime import datetime, time, timedelta
import pytz

Đã thêm 10 phút trên datetime cơ sở dữ liệu

table_datetime = '2019-06-13 07: 49: 02.832969' (ví dụ)

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

Nó làm việc cho tôi.


0

Chỉ:

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

Vì vậy, làm điều này:

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

và sau đó sử dụng start_timeend_time

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.