如何仅使用标准库将UTC日期时间转换为本地日期时间?
如何在只使用标准库的情况下将UTC日期时间转换为本地日期时间?
Python 3.9添加了`zoneinfo`模块,因此现在可以通过以下方式完成(仅使用标准库):
from zoneinfo import ZoneInfo from datetime import datetime utc_unaware = datetime(2020, 10, 31, 12) # 从数据库加载 utc_aware = utc_unaware.replace(tzinfo=ZoneInfo('UTC')) # 使其具有时区信息 local_aware = utc_aware.astimezone(ZoneInfo('localtime')) # 转换为本地时间
中欧比UTC提前1或2个小时,因此`local_aware`为:
datetime.datetime(2020, 10, 31, 13, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='localtime'))
以字符串形式表示为:
2020-10-31 13:00:00+01:00
Windows没有系统时区数据库,因此需要安装额外的包:
pip install tzdata
有一个兼容版本可以在Python 3.6到3.8中使用:
sudo pip install backports.zoneinfo
然后:
from backports.zoneinfo import ZoneInfo
在这里,甚至不需要使用`zoneinfo`模块 - 可以参考jfs的回答的第一部分(适用于Python 3.3+);-)
我认为`ZoneInfo('localtime')`比`tz=None`更清晰(毕竟,人们可能希望`tz=None`删除时区或返回UTC而不是本地时间)。
此外,问题可能涉及到用户拥有网站并希望以用户的本地时间显示时间戳。为此,需要将其转换为用户明确的时区,而不是本地时间。
关于Win10的说明可能是正确的,因为Python 3.9不再使用它,但Win10自Windows 10 1703(于2017年发布)以来就包含了IANA ICU数据,并在1903中进行了改进。根据Raymond Chen的说法,他们现在建议应用程序使用它而不是Windows注册表TZ数据。[devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255](https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255)
安装了`tzdata`后,在Windows上会出现错误。它抱怨`ZoneInfo('localtime')`。错误信息为:`zoneinfo._common.ZoneInfoNotFoundError: No time zone found with key localtime`。
如何仅使用标准库将UTC日期时间转换为本地日期时间?
Python 3.9以后,可以使用`zoneinfo`模块来实现。首先,使用`utcnow()`获取当前时间:
from datetime import datetime database_time = datetime.utcnow() database_time
然后创建时区:
from zoneinfo import ZoneInfo utc = ZoneInfo('UTC') localtz = ZoneInfo('localtime')
接下来进行转换。要在不同时区之间进行转换,需要告诉`datetime`对象它所在的时区,然后使用`astimezone()`方法:
utctime = database_time.replace(tzinfo=utc) localtime = utctime.astimezone(localtz) localtime
对于Python 3.6到3.8的版本,需要使用`backports.zoneinfo`模块:
try: from zoneinfo import ZoneInfo except ImportError: from backports.zoneinfo import ZoneInfo
其他版本需要使用`pytz`或`dateutil`库。`dateutil`的用法与`zoneinfo`类似:
from dateutil import tz utc = tz.gettz('UTC') localtz = tz.tzlocal() utctime = now.replace(tzinfo=UTC) localtime = utctime.astimezone(localtz) localtime
`pytz`库具有不同的接口,这是由于Python的时区处理不支持处理模糊时间造成的:
import pytz utc = pytz.timezone('UTC') # 没有本地时区的支持,需要知道所在时区 localtz = pytz.timezone('Europe/Paris') utctime = utc.localize(database_time) localtime = localtz.normalize(utctime.astimezone(localtz)) localtime
如果需要完整的解决方案,可以在需要时参考上述代码。`dateutil`和`pytz`现在都支持Python 3。
`dateutil`无法区分在夏令时更改期间发生的两个1:30时间。如果需要能够区分这两个时间,可以使用`pytz`来处理。
为什么不使用简单的`datetime.now(timezone.utc)`,而要使用混乱的`utcnow`加上额外的替换步骤?另外,`ZoneInfo('localtime')`是特定于平台的。
问题的出现的原因是要将一个UTC的日期时间转换为本地日期时间,但只能使用标准库进行转换。 解决方法有三种。
第一种方法是在Python 3.3+版本中使用datetime和timezone库。通过将时区信息设置为UTC并将其转换为本地时区,可以将UTC日期时间转换为本地日期时间。
第二种方法是在Python 2/3版本中使用calendar和datetime库。通过获取整数时间戳来避免精度丢失,并使用fromtimestamp函数将其转换为本地日期时间。
第三种方法是使用pytz库。首先,通过引入pytz库并设置本地时区,可以将UTC日期时间转换为本地日期时间。然后,使用normalize函数来规范化日期时间。
下面是一个示例,展示了如何使用这些方法将UTC日期时间转换为本地日期时间。在示例中,使用utc_to_local函数将给定的UTC日期时间转换为本地日期时间,并使用strftime函数将其格式化为特定的日期时间字符串。
Python 3.3的输出结果为:
2010-06-06 21:29:07.730000 MSD+0400
2010-12-06 20:29:07.730000 MSK+0300
2012-11-08 14:19:50.093745 MSK+0400
Python 2的输出结果为:
2010-06-06 21:29:07.730000
2010-12-06 20:29:07.730000
2012-11-08 14:19:50.093911
pytz的输出结果为:
2010-06-06 21:29:07.730000 MSD+0400
2010-12-06 20:29:07.730000 MSK+0300
2012-11-08 14:19:50.146917 MSK+0400
注意:这些方法会考虑到夏令时(DST)和最近的时区偏移变化。但不清楚非pytz解决方案是否适用于Windows操作系统。
关于normalize函数的作用,它是用来规范化日期时间的。具体信息可以参考pytz: Why is normalize needed when converting between timezones?。
如果尝试使用pytz解决方案时出现TypeError: replace() takes no keyword arguments错误,可以尝试使用local_dt.replace(tzinfo=None).astimezone(tz=timezone.utc)来实现从本地时区到UTC时区的转换。
最后,DST在这里表示夏令时(Daylight Saving Time)。