我有一个使用datetime.utcnow()创建的python datetime实例,并持久化在数据库中。

为了显示,我想使用默认的本地时区将从数据库检索到的datetime实例转换为本地datetime(即,就像使用datetime.now()创建的datetime一样)。

如何将UTC日期时间转换为本地日期时间仅使用python标准库(例如,没有pytz依赖)?

一种解决方案似乎是使用datetime.astimezone(tz),但是如何获得默认的本地时区呢?


当前回答

Python 3.9添加了zoneinfo模块,所以现在可以这样做(仅限stdlib):

from zoneinfo import ZoneInfo
from datetime import datetime

utc_unaware = datetime(2020, 10, 31, 12)  # loaded from database
utc_aware = utc_unaware.replace(tzinfo=ZoneInfo('UTC'))  # make aware
local_aware = utc_aware.astimezone(ZoneInfo('localtime'))  # convert

中欧比UTC早1或2小时,因此local_aware为:

datetime.datetime(2020, 10, 31, 13, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='localtime'))

#,只要str:

2020-10-31 13:00:00+01:00

Windows没有系统时区数据库,所以这里需要一个额外的包:

pip install tzdata  

在Python 3.6到3.8中允许使用一个backport:

sudo pip install backports.zoneinfo

然后:

from backports.zoneinfo import ZoneInfo

其他回答

根据阿列克谢的评论。这也适用于DST。

import time
import datetime

def utc_to_local(dt):
    if time.localtime().tm_isdst:
        return dt - datetime.timedelta(seconds = time.altzone)
    else:
        return dt - datetime.timedelta(seconds = time.timezone)

我发现的最简单的方法是得到你所处位置的时间偏移量,然后从小时中减去它。

def format_time(ts,offset):
    if not ts.hour >= offset:
        ts = ts.replace(day=ts.day-1)
        ts = ts.replace(hour=ts.hour-offset)
    else:
        ts = ts.replace(hour=ts.hour-offset)
    return ts

在Python 3.5.2中,这对我来说是可行的。

标准的Python库根本没有任何tzinfo实现。我一直认为这是datetime模块的一个惊人缺点。

tzinfo类的文档中确实提供了一些有用的示例。在小节的末尾寻找大代码块。

Python 3.9添加了zoneinfo模块,所以现在可以这样做(仅限stdlib):

from zoneinfo import ZoneInfo
from datetime import datetime

utc_unaware = datetime(2020, 10, 31, 12)  # loaded from database
utc_aware = utc_unaware.replace(tzinfo=ZoneInfo('UTC'))  # make aware
local_aware = utc_aware.astimezone(ZoneInfo('localtime'))  # convert

中欧比UTC早1或2小时,因此local_aware为:

datetime.datetime(2020, 10, 31, 13, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='localtime'))

#,只要str:

2020-10-31 13:00:00+01:00

Windows没有系统时区数据库,所以这里需要一个额外的包:

pip install tzdata  

在Python 3.6到3.8中允许使用一个backport:

sudo pip install backports.zoneinfo

然后:

from backports.zoneinfo import ZoneInfo

针对特定情况: 输入utc datetime字符串。//通常来自日志 输出区域日期时间字符串。


def utc_to_locale(utc_str):
    # from utc to locale
    d1=datetime.fromisoformat(utc_str+'-00:00')
    return d1.astimezone().strftime('%F %T.%f')[:-3]

测试:

>>> utc_to_locale('2022-02-14 00:49:06')
'2022-02-14 08:49:06.000'
>>> utc_to_locale('2022-02-14 00:49:06.123')
'2022-02-14 08:49:06.123'
>>> utc_to_locale('2022-02-14T00:49:06.123')
'2022-02-14 08:49:06.123'