如何在Python中将naive日期时间转换为DST感知的日期时间?

How do you convert a naive datetime to DST-aware datetime in Python?

我目前正在为一个返回naive 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进行存储,以便用户更改时区时,现有事件仍将在计划的正确时间呈现。

前端在我的控制范围之外,所以我无法更改我接收的数据。数据库设计也在我的控制范围之外,所以我不能更改正在存储的数据和存储方式。

以下是我迄今为止采取的大致方法:

1
2
3
4
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)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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

请注意,使用"replace"将时区设置为pst而不是pdt,而不管日期是什么,这将使它的UTC偏移量为8小时,而不是预期的7小时dst偏移量,因此最终会错误地保存时间。

对于将原始日期时间转换为正确的PDT(或其他时区相关DST)TZINFO,我有哪些选择?

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


pytz的localize函数可以这样做:http://pytz.sourceforge.net/本地化时间和日期算法

1
2
3
4
5
6
7
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