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

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

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

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


当前回答

这是一种糟糕的方法,但它避免了定义。它满足了坚持使用基本的Python3库的要求。

# Adjust from UST to Eastern Standard Time (dynamic)
# df.my_localtime should already be in datetime format, so just in case
df['my_localtime'] = pd.to_datetime.df['my_localtime']

df['my_localtime'] = df['my_localtime'].dt.tz_localize('UTC').dt.tz_convert('America/New_York').astype(str)
df['my_localtime'] = pd.to_datetime(df.my_localtime.str[:-6])

其他回答

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

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

这是一种糟糕的方法,但它避免了定义。它满足了坚持使用基本的Python3库的要求。

# Adjust from UST to Eastern Standard Time (dynamic)
# df.my_localtime should already be in datetime format, so just in case
df['my_localtime'] = pd.to_datetime.df['my_localtime']

df['my_localtime'] = df['my_localtime'].dt.tz_localize('UTC').dt.tz_convert('America/New_York').astype(str)
df['my_localtime'] = pd.to_datetime(df.my_localtime.str[:-6])

使用timedelta在时区之间切换。您所需要的只是时区之间的小时偏移量。不必为datetime对象的所有6个元素设置边界。Timedelta也可以轻松处理闰年、闰世纪等。你必须首先

from datetime import datetime, timedelta

如果offset是时区的delta(以小时为单位):

超时 = 时间 + 时间增量(小时 = 偏移量)

其中timein和timeout是datetime对象。如。

时间 + 时间增量(小时 = -8)

从格林尼治标准时间转换为太平洋标准时间。

那么,如何确定偏移量呢?这里是一个简单的函数,前提是你只有一些转换的可能性,而不使用时区“感知”的datetime对象,而其他一些答案很好地做到了。有点手动,但有时清晰是最好的。

def change_timezone(timein, timezone, timezone_out):
    '''
    changes timezone between predefined timezone offsets to GMT
    timein - datetime object
    timezone - 'PST', 'PDT', 'GMT' (can add more as needed)
    timezone_out - 'PST', 'PDT', 'GMT' (can add more as needed)
    ''' 
    # simple table lookup        
    tz_offset =  {'PST': {'GMT': 8, 'PDT': 1, 'PST': 0}, \
                  'GMT': {'PST': -8, 'PDT': -7, 'GMT': 0}, \
                  'PDT': {'GMT': 7, 'PST': -1, 'PDT': 0}}
    try:
        offset = tz_offset[timezone][timezone_out]
    except:
        msg = 'Input timezone=' + timezone + ' OR output time zone=' + \
            timezone_out + ' not recognized'
        raise DateTimeError(msg)

    return timein + timedelta(hours = offset)

在看了大量的答案和我能想到的最严格的代码之后(目前),似乎最好的是所有应用程序,其中时间是重要的,混合时区必须考虑在内,应该真正努力使所有datetime对象“感知”。那么,最简单的答案似乎是:

timeout = timein.astimezone(pytz.timezone("GMT"))

例如,转换为格林尼治时间。当然,要转换到或从您希望的任何其他时区(本地或其他时区),只需使用pytz理解的适当的时区字符串(来自pytz.all_timezones)。日光节约时间也被考虑在内。

使用时间。timezone,它给出一个“UTC以西秒数”的整数。

例如:

from datetime import datetime, timedelta, timezone
import time

# make datetime from timestamp, thus no timezone info is attached
now = datetime.fromtimestamp(time.time())

# make local timezone with time.timezone
local_tz = timezone(timedelta(seconds=-time.timezone))

# attach different timezones as you wish
utc_time = now.astimezone(timezone.utc)
local_time = now.astimezone(local_tz)

print(utc_time.isoformat(timespec='seconds')) 
print(local_time.isoformat(timespec='seconds'))

在我的PC上(Python 3.7.3),它给出:

2021-05-07T12:50:46+00:00
2021-05-07T20:50:46+08:00

非常简单,只使用标准库~

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