Jay*_*Jay 13 python timezone datetime pytz
我目前正在为后端系统工作,该系统返回天真的Python日期时间.前端的工作方式是用户创建各种日历事件,前端返回他们创建的事件的天真版本(例如,如果用户选择2020年10月5日下午3:00至4:00,前端返回datetime.datetime(2020,10,5,15,0,0)作为start和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)
Run Code Online (Sandbox Code Playgroud)
我遇到的问题与夏令时有关:
>>> 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
Run Code Online (Sandbox Code Playgroud)
请注意,使用'replace'将时区设置为PST而不是PDT,无论日期如何,这使得它的UTC偏移量为8小时而不是预期的7小时DST偏移量,因此时间最终会被错误地保存.
将天真日期时间转换为正确的PDT(或其他时区相对DST)tzinfo,我有哪些选择?
(另外,请注意,并非所有用户都生活在观察夏令时的时区,或者可能生活在不同时间切换的时区,所以为了在保存之前做一个像timedelta校正的解决方案,我需要知道是否时区支持DST,以及它切换的日期.
Mar*_*som 19
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
Run Code Online (Sandbox Code Playgroud)
MrF*_*pes 10
来自zoneinfoPython 3.9 的标准库:
from datetime import datetime
from zoneinfo import ZoneInfo
naive_datetime = datetime(2011, 10, 26, 12, 0, 0)
user_tz_preference = ZoneInfo("America/Los_Angeles") # former 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("America/Los_Angeles"))
# 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
Run Code Online (Sandbox Code Playgroud)