Python: astimezone (None) memberikan datetime yang sadar, tidak mengetahui DST

Oct 26 2020

astimezone(None)adalah cara mudah untuk melokalkan objek datetime ke waktu lokal, misalnya setelan OS Anda ( dokumen , contoh ). Namun, saya mencatat ada peringatan. Karena saya menggunakan CET / CEST dan kami baru saja melakukan perubahan DST, saya bermain-main dengan waktu dan waktu yang sadar. 1

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

t_DSTactive = datetime(2020,10,23, tzinfo=ZoneInfo('Europe/Berlin'))
t_DSTinactive = datetime(2020,10,26, tzinfo=ZoneInfo('Europe/Berlin'))
print(t_DSTinactive - t_DSTactive)
# 3 days, 0:00:00

Seperti yang diharapkan, timedeltaperbedaan waktu menunjukkan dinding 2 , yaitu 3 hari antara waktu tersebut. Karena perubahan dari DST aktif menjadi DST tidak aktif, durasi dalam UTC adalah 3 hari dan 1 jam:

t_DSTactive = t_DSTactive.astimezone(timezone.utc)
t_DSTinactive = t_DSTinactive.astimezone(timezone.utc)
print(t_DSTinactive - t_DSTactive)
# 3 days, 1:00:00

Menggunakan asttimezone(None)untuk melokalkan, semuanya tampak baik-baik saja (UTC + 2 → UTC + 1):

DSTinactive = datetime(2020,10,26).astimezone(None)
print(DSTactive, DSTinactive)
# 2020-10-23 00:00:00+02:00 2020-10-26 00:00:00+01:00

... tetapi timedeltatermasuk +1 jam dari transisi DST:

print(DSTinactive - DSTactive)
# 3 days, 1:00:00

Apa yang terjadi disini?


  • 1 Saya menggunakan MS Windows 10; hasil mungkin berbeda di platform lain
  • 2 lihat juga: Semantik aritmatika tanggal waktu sadar-zona

Jawaban

MrFuppes Oct 26 2020 at 10:37

Melihat repr()objek datetime yang diperoleh dengan .astimezone(None), kita melihat bahwa tzinfoatribut "hanya" a timedeltadalam kedua kasus:

print(repr(DSTactive))
print(repr(DSTinactive))
# datetime.datetime(2020, 10, 23, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200), 'Mitteleuropäische Sommerzeit'))
# datetime.datetime(2020, 10, 26, 0, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'Mitteleuropäische Zeit'))

Pengimbangan UTC tetap dengan kata lain, bukan zona waktu dalam arti geografis (termasuk perubahan DST yang ditentukan). Offset tetap tentu saja tidak mengetahui perubahan DST. Dengan mempertimbangkan offset, perhitungannya benar memberikan 3 hari, selisih 1 jam.

Latar belakang: Dalam src datetime, kita melihat bahwaastimezone(None)panggilan_local_timezone()untuk mendapatkan tzinfo, yang mengembalikannya sebagai offset tetap.

Meskipun nyaman, astimezone(None)dapat menyebabkan hasil yang tidak terduga di sini. Cara untuk mengatasi masalah ini tentu saja dengan melokalkan tanggal waktu ke zona waktu lokal. tzlocal bisa sangat membantu di sini, terutama di Windows yang sangat enggan memberikan nama zona waktu.