【问题标题】:How do you convert a naive datetime to DST-aware datetime in Python?如何在 Python 中将天真的日期时间转换为可识别 DST 的日期时间?
【发布时间】:2011-12-20 16:02:45
【问题描述】:

我目前正在开发一个日历系统的后端,该系统返回朴素的 Python 日期时间。前端的工作方式是用户创建各种日历事件,前端返回他们创建的事件的原始版本(例如,如果用户选择 2020 年 10 月 5 日下午 3:00-4:00,则前端返回datetime.datetime(2020, 10, 5, 15, 0, 0) 作为开始,datetime.datetime(2011, 10, 5, 16, 0, 0) 作为结束。

我需要做的是获取天真的日期时间并将其转换为 UTC 以存储在数据库中。系统的每个用户都已经指定了他们的时区偏好,因此天真的日期时间被认为是与他们的时区偏好相同的时区。显然,日期时间需要相对于 UTC 进行存储,这样如果用户更改时区,现有事件仍将在他们安排的正确时间呈现。

前端不在我的控制范围内,因此我无法更改收到的数据。数据库设计也超出了我的控制范围,因此我无法更改存储的数据以及存储方式。

这是我目前采取的大致方法:

import pytz
def convert_to_UTC(naive_datetime, user_tz_preference):
    user_datetime = naive_datetime.replace(tzinfo=user_tz_preference)
    utc_datetime = user_datetime.astimezone(pytz.utc)

我遇到的问题与夏令时有关:

>>> from datetime import datetime
>>> import pytz
>>> user_tz_preference = pytz.timezone('US/Pacific')
>>> naive_datetime = datetime(2011, 10, 26, 12, 0, 0)
>>> user_datetime = naive_datetime.replace(tzinfo=user_tz_preference)
>>> user_datetime
datetime.datetime(2011, 10, 26, 12, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)
>>> received_utc = user_datetime.astimezone(pytz.utc)
>>> received_utc
datetime.datetime(2011, 10, 26, 20, 0, tzinfo=<UTC>)
>>> expected_utc = datetime(2011, 10, 26, 19, 0, tzinfo=pytz.utc)
>>> expected_utc == received_utc
False

请注意,无论日期如何,使用“替换”都会将时区设置为 PST 而不是 PDT,这使其 UTC 偏移量为 8 小时,而不是预期的 7 小时 DST 偏移量,因此最终会错误地保存时间。

我有哪些选项可以将天真的日期时间转换为正确的 PDT(或其他与时区相关的 DST)tzinfo?

(另外,请注意,并非所有用户都生活在遵守 DST 的时区,或者可能生活在在不同时间切换的时区,因此为了在保存之前执行时间增量校正等解决方案,我需要了解时区是否支持 DST,以及在哪个日期切换)。

【问题讨论】:

标签: python datetime timezone pytz


【解决方案1】:

Pytz 的localize 函数可以做到这一点:http://pytz.sourceforge.net/#localized-times-and-date-arithmetic

from datetime import datetime
import pytz    

tz = pytz.timezone('US/Pacific')
naive_dt = datetime(2020, 10, 5, 15, 0, 0) 
utc_dt = tz.localize(naive_dt, is_dst=None).astimezone(pytz.utc)
# -> 2020-10-05 22:00:00+00:00

【讨论】:

  • 谢谢。这似乎就是我想要的。
【解决方案2】:

使用来自 Python 3.9 标准库的 zoneinfo

from datetime import datetime
from zoneinfo import ZoneInfo   

naive_datetime = datetime(2011, 10, 26, 12, 0, 0)
user_tz_preference = ZoneInfo('US/Pacific')

# it is safe to replace the tzinfo:
user_datetime = naive_datetime.replace(tzinfo=user_tz_preference)
# ...or set it directly:
user_datetime = datetime(2011, 10, 26, 12, tzinfo=ZoneInfo('US/Pacific'))

# astimezone works as before:
utc_datetime = user_datetime.astimezone(ZoneInfo('UTC'))

print(repr(user_datetime))
# datetime.datetime(2011, 10, 26, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='US/Pacific'))
print(user_datetime.isoformat())
# 2011-10-26T12:00:00-07:00
print(utc_datetime.isoformat())
# 2011-10-26T19:00:00+00:00

docs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-26
    • 2022-09-23
    • 1970-01-01
    • 2010-12-28
    • 2014-07-06
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多