datetime.now(tz) 和 datetime(year, month, day, tzinfo=tz) 没有相同的 UTC 偏移量

Posted

技术标签:

【中文标题】datetime.now(tz) 和 datetime(year, month, day, tzinfo=tz) 没有相同的 UTC 偏移量【英文标题】:datetime.now(tz) and datetime(year, month, day, tzinfo=tz) don't have same UTC offset 【发布时间】:2020-12-01 15:49:25 【问题描述】:

为什么在下面的代码中创建的 2 个日期时间中的 UTC 偏移量不同?我正在使用 pytz==2019.1

from datetime import datetime
import pytz

EASTERN = pytz.timezone('US/Eastern')
dt1 = datetime.now(EASTERN)
dt2 = datetime(2020, 8, 11, 15, 30, tzinfo=EASTERN)
print(f'dt1: dt1')
print(f'dt2: dt2')

结果:

dt1: 2020-08-11 18:35:47.984745-04:00

dt2: 2020-08-11 15:30:00-04:56

第一个显示的 UTC 偏移量为 -04:00,这是正确的(对于一年中的这个时候),但第二个显示的 UTC 偏移量为 -04:56。

如何使用第二种方法声明日期时间并从第一种方法获取 UTC 偏移量。

【问题讨论】:

您正在将系统时间(现在)与您自己提供的某个时间(2020 年 8 月 11 日 15 日 30 日)进行比较 旁注:您的pytz 已过时。建议:使用dateutil 而不是pytz 以避免这种奇怪的行为。阅读this blogpost 以获取更多信息为什么会这样。 @MrFuppes,你的评论是正确的。在阅读了链接博客的前几段之后,我明白了发生了什么。你能把它放在一个答案中,我会把它标记为答案吗? 从@MrFuppes 分享的博文中,他们实际上在pytz's time zone model 下引用了同样的问题 【参考方案1】:

关于dt1

datetime.now() 将从 UTC 返回 tzinfo。如果您执行以下操作,您可以看到这一点:

>>> repr(EASTERN.fromutc(datetime.now()))
"datetime.datetime(2020, 8, 11, 12, 33, 28, 849873, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)"

tz.fromutc()datetime.now() 在幕后所做的。

关于dt2

如果您查看 EASTERN 的 repr,您将看到以下内容:

>>> repr(EASTERN)
"<DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>"
>>> repr(dt2)
"datetime.datetime(2020, 8, 11, 15, 30, tzinfo=<DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>)"

我对时区差异不太满意,所以我不想把你引向错误的方向,但据我所知,这两个选项会产生相同的结果:

dt2 = datetime(2020, 8, 11, 15, 30, tzinfo=EASTERN)
dt2_eastern_corrected = EASTERN.fromutc(dt2)
dt3 = datetime(2020, 8, 11, 15, 30)
dt3_eastern_corrected = EASTERN.fromutc(dt3

>>> repr(dt2_eastern_corrected)
"datetime.datetime(2020, 8, 11, 11, 30, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)"
>>> repr(dt3_eastern_corrected)
"datetime.datetime(2020, 8, 11, 11, 30, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)"

【讨论】:

也许我应该更清楚;我要说的是,如果你按照面包屑导航,你会看到datetime._fromtimestamp() 如果tz 被传递到datetime.now() 将返回`tz.fromutc(result)`。 实际上,您的代码的第二部分(使用pytz.timezone.fromutc)非常有趣,我认为这会检索日期时间对象的内部时间戳(POSIX),而忽略 tzinfo? 我不太确定那部分,如果那是BaseTzInfo.fromutc 所做的,那么可能,但从快速检查you can see 来看,它可以一步完成本地化。 刚刚意识到这是wrapper over datetime.tzinfo。我不太确定tzinfo.fromutc 的算法是什么,但你可以阅读它here。 至少我认为我的假设是错误的,它与 POSIX 时间戳无关。如果传递的 datetime 对象的 tzinfo 为 None,则调用 localize。如果设置了 tzinfo,它会有点难以理解,但似乎 tzinfo 基本上只是被覆盖了。不过,我不确定我是否完全明白……【参考方案2】:

显示代码的问题是datetime.now(tz) 可以将pytz.timezone 作为tz 参数处理,而默认构造函数datetime(y,m,d,...) 不能。在这种情况下,你必须使用timezonelocalize方法,

from datetime import datetime
import pytz

EASTERN = pytz.timezone('US/Eastern')
dt1 = datetime.now(EASTERN)
dt2 = EASTERN.localize(datetime(2020, 8, 11, 15, 30))
print(f'dt1: dt1')
print(f'dt2: dt2')
# prints
# dt1: 2020-08-12 10:07:09.738763-04:00
# dt2: 2020-08-11 15:30:00-04:00

dateutil 避免了这个问题,更多信息可以在here 找到。这将使代码“按原样”工作:

from dateutil.tz import gettz

EASTERN = gettz('US/Eastern')
dt1 = datetime.now(EASTERN)
dt2 = datetime(2020, 8, 11, 15, 30, tzinfo=EASTERN)
print(f'dt1: dt1')
print(f'dt2: dt2')
# prints e.g.
# dt1: 2020-08-12 10:20:07.796811-04:00
# dt2: 2020-08-11 15:30:00-04:00

此外,pytz 很可能是 deprecated with Python 3.9,因为您会将 zoneinfo 作为此类作业的标准库的一部分。

【讨论】:

以上是关于datetime.now(tz) 和 datetime(year, month, day, tzinfo=tz) 没有相同的 UTC 偏移量的主要内容,如果未能解决你的问题,请参考以下文章

datetime处理日期和时间

datetime shutil xml collections模块

DateTime.UtcNow.ToString() 和DateTime.Now.ToString()输出的字符为啥不一样呢?

django 1.4 timezone.now() 与 datetime.datetime.now()

datetime处理日期和时间

datetime处理日期和时间