datetimes
,一个代表时间更改之前的某个时间,另一个代表第一个
datetime
之后一个日历日的同一时间。我预计这两个对象之间的时间差不会正好是一天,但这就是我所看到的(使用 python3.8,这是我必须使用的所有内容)。取与
datetimes
关联的 timestamps
的差异,返回的正是我期望看到的内容。在我看来,当
datetime
对象跨越时间变化时,它们的差异看起来完全是错误的。这是预期的行为吗?
from datetime import datetime, timedelta
from dateutil.tz import gettz # pip install dateutil
def iso(dt):
return dt.strftime('%FT%T%z')
# Daylight saving time begins at 2 a.m. local time on Sunday, March 10, 2024
us_central = gettz('US/Central')
before = datetime(2024, 3, 9, 15, 22, 1, tzinfo=us_central)
after = datetime(2024, 3, 10, 15, 22, 1, tzinfo=us_central)
print()
print(f'before time change: {iso(before)}')
print(f' after time change: {iso(after)}')
naive = after - before
by_timestamps = timedelta(seconds = after.timestamp() - before.timestamp())
difference_difference = naive.total_seconds() - by_timestamps.total_seconds()
print()
print('Differences:')
print(f' naive: {repr(naive)}')
print(f'by timestamps: {repr(by_timestamps)}')
print(f' error: {difference_difference}s')
输出(python3.8)
before time change: 2024-03-09T15:22:01-0600
after time change: 2024-03-10T15:22:01-0500
Differences:
naive: datetime.timedelta(days=1)
by timestamps: datetime.timedelta(seconds=82800)
error: 3600.0s
cpython 的源代码(纯 Python 后备模块,尽管我希望结果与 C 代码相同):
class datetime:
...
def __sub__(self, other):
"Subtract two datetimes, or a datetime and a timedelta."
if not isinstance(other, datetime):
if isinstance(other, timedelta):
return self + -other
return NotImplemented
days1 = self.toordinal()
days2 = other.toordinal()
secs1 = self._second + self._minute * 60 + self._hour * 3600
secs2 = other._second + other._minute * 60 + other._hour * 3600
base = timedelta(days1 - days2,
secs1 - secs2,
self._microsecond - other._microsecond)
if self._tzinfo is other._tzinfo:
return base
myoff = self.utcoffset()
otoff = other.utcoffset()
if myoff == otoff:
return base
if myoff is None or otoff is None:
raise TypeError("cannot mix naive and timezone-aware time")
return base + otoff - myoff
请注意,没有代码可以解释夏令时的变化。
因此,我建议在执行任何 timedelta 计算之前将日期时间对象本地化为 UTC。如果你的代码需要精确到秒,请注意 Python 也会忽略闰秒,甚至 Unix 时间(由
.timestamp()
生成)也会做出错误的选择。在闰秒周围减去两个 Unix 时间戳将会减少一,因为即使时间戳看起来独立于日历,它们也被修补以向后兼容假设每天固定秒数的代码。