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,...)
不能。在这种情况下,你必须使用timezone
的localize
方法,
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 shutil xml collections模块
DateTime.UtcNow.ToString() 和DateTime.Now.ToString()输出的字符为啥不一样呢?