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

发布于 12-13 21:07 字数 1642 浏览 5 评论 0原文

我目前正在开发一个返回简单 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 小时,而不是预计 DST 偏移 7 小时,所以时间最终被错误地保存了。

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

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

I'm currently working on the backend for a calendaring system that returns naive Python datetimes. The way the front end works is the user creates various calendar events, and the frontend returns the naive version of the event they created (for example, if the user selects October 5, 2020 from 3:00pm-4:00pm, the frontend returns datetime.datetime(2020, 10, 5, 15, 0, 0) as the start and datetime.datetime(2011, 10, 5, 16, 0, 0) as the end.

What I need to do is to take the naive datetime and convert it into UTC for storage in a database. Each user of the system has already specified their timezone preference, so the naive datetime is considered to be of the same timezone as their timezone preference. Obviously the datetimes need to be stored relative to UTC so that if users change their timezone, existing events will still render at the correct time that they scheduled them.

The frontend is outside my control, so I can't change the data that I'm receiving. The database design is also outside my control, so I can't change what data is being stored and how.

Here is the approximate approach I have taken so far:

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)

The problem I ran into is related to Daylight Savings Time:

>>> 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

Notice that using 'replace' sets the timezone to PST instead of PDT regardless of the date, which gives it a UTC offset of 8 hours instead of the expected 7 hours DST offset, so the time ends up being saved incorrectly.

What options do I have for converting the naive datetime to the correct PDT (or other timezone-relative DST) tzinfo?

(Also, please note that not all users live in a timezone that observes DST, or may live in a timezone that switches over at different times, so in order to do a solution like a timedelta correction before saving, I would need to know if the timezone supports DST, and on which dates it switches over).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

往日情怀2024-12-20 21:07:10

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

Pytz's localize function can do this: 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
狂之美人2024-12-20 21:07:10

使用 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("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

docs

With zoneinfo from Python 3.9's standard lib:

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

docs

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文