如何仅使用标准库将UTC日期时间转换为本地日期时间?

22 浏览
0 Comments

如何仅使用标准库将UTC日期时间转换为本地日期时间?

我有一个使用datetime.utcnow()创建的Python datetime实例,并且将其持久化到数据库中。\n为了显示,我希望将从数据库中检索到的datetime实例转换为使用默认本地时区的本地datetime(即,就好像datetime.now()创建的那样)。\n如何使用仅使用Python标准库(例如,没有pytz依赖)将UTC datetime转换为本地datetime?\n似乎一个解决方案是使用datetime.astimezone(tz),但是如何获取默认的本地时区呢?

0
0 Comments

如何在只使用标准库的情况下将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`。

0
0 Comments

如何仅使用标准库将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')`是特定于平台的。

0
0 Comments

问题的出现的原因是要将一个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)。

0