简体   繁体   English

Python 日期时间库,在向日期时间添加天数时可以识别夏令时

[英]Python datetime library that is daylight savings aware when adding days to datetime

Is there a python datetime library that does this?是否有执行此操作的 python 日期时间库?

dt = iso8601.parse_date("2016-03-13 00:00:00-08")
dt = dt.astimezone(us_pacific)
dt += timedelta(days=1)
self.assertEqual(dt, iso8601.parse_date("2016-03-14 00:00:00-07"))

In other words, I'm looking for a library where the datetime object is smart enough to know that timedelta(days=1) is NOT the same as timedelta(hours=24) (bonus points for supporting months).换句话说,我正在寻找一个库,其中 datetime 对象足够聪明,知道 timedelta(days=1) 与 timedelta(hours=24) 不同(支持月份的奖励积分)。

Currently, I'm finding the least bug-hazard workaround is to use dates and then convert that to a datetime with the time set to 0 in the given timezone.目前,我发现错误风险最小的解决方法是使用日期,然后将其转换为日期时间,并在给定时区将时间设置为 0。 The issue though is that its easy to assume the code above will work as given, so I would like to work with a library where that is not a risk.但问题是很容易假设上面的代码会按给定的方式工作,所以我想使用一个没有风险的库。 Likewise, if you're given a datetime object, its a nuisance to convert back into dates.同样,如果给定了一个日期时间对象,将其转换回日期也很麻烦。

Edit:编辑:

This was put on hold since asking if there is a software library that accomplishes a task vs. having to code it out by scratch is offtopic.这被搁置了,因为询问是否有一个软件库可以完成一项任务,而不是必须从头开始编写代码是离题的。 I'm not sure how to better phrase, since I've already explained the workaround is to work with dates and then add the time later, which can be done in various ways.我不确定如何更好地表达,因为我已经解释过解决方法是使用日期然后添加时间,这可以通过多种方式完成。 I'm looking for a BETTER way, which I already know isn't part of the python standard library.我正在寻找一种更好的方法,我已经知道它不是 python 标准库的一部分。 I'm pretty sure asking "is there a better way to do this?", or "how can I get accomplish this in about the same number of lines of code?"我很确定会问“有没有更好的方法来做到这一点?”,或者“我怎样才能用大约相同数量的代码行来完成这个?” are perfectly valid questions as well.也是完全有效的问题。

If there's no library that does such a thing, I could certainly make it.如果没有图书馆做这样的事情,我当然可以做到。 I'd call it YADateTime because it would be yet another python date time library.我将其称为 YADateTime,因为它将是另一个 Python 日期时间库。 That said, if there's already a library there's no point in me making one.也就是说,如果已经有一个图书馆,那么我再建一个就没有意义了。

This worked for me on Python 3.6.4. 这在Python 3.6.4上对我有用。 The day was added correctly according to the timezone-aware datetime objects (ie the date incremented and the hour stayed at 0). 根据时区感知的日期时间对象(即日期增加且小时保持为0)正确添加了日期。 The problem I had was that the timezone offset was not correct. 我遇到的问题是时区偏移是不正确的。

Not pretty, but it seems to work. 不漂亮,但它似乎工作。

EST = pytz.timezone('US/Eastern')
DAY = dt.timedelta(days = 1)

date = date + DAY
date_with_correct_timezone = EST.localize(dt.datetime(date.year,date.month,date.day,hour,minute,0))
if date != date_with_correct_timezone:
    print(f'     corrected {date} to {date_with_correct_timezone}')
    date = date_with_correct_timezone

Example Output: 示例输出:

corrected 2017-03-13 00:00:00-05:00 to 2017-03-13 00:00:00-04:00
corrected 2017-11-06 00:00:00-04:00 to 2017-11-06 00:00:00-05:00

This is an old question, but it's a useful question, and I didn't find any newer version of it on SO, so I'm adding an answer here.这是一个老问题,但它是一个有用的问题,我没有在 SO 上找到它的任何更新版本,所以我在这里添加一个答案。

At minimum, one should be able to take a datetime of 2022-03-13 01:30:00 in the America/Chicago timezone, which is just before the DST "spring forward" from 2am to 3am, add an hour to it, and get 2022-03-13 03:30:00 in the same America/Chicago time zone.至少,应该能够在America/Chicago时区采用2022-03-13 01:30:00的日期时间,也就是夏令时从凌晨 2 点到凌晨 3 点“向前推进”之前,再加一个小时,并在同一America/Chicago时区获得2022-03-13 03:30:00

This isn't even adding an interval of varying length, it's just crossing a DST boundary, so it should be "easy".这甚至没有添加不同长度的间隔,它只是跨越 DST 边界,所以它应该是“容易的”。

The following things fail that all look like they should work:以下事情失败了,但看起来它们应该可以工作:

# 0a. pytz timezone, datetime.timedelta math
import pytz
from datetime import datetime, timedelta
tz = pytz.timezone('America/Chicago')
d = datetime(2022, 3, 13, 1, 30, tzinfo=tz)  # already well-known to be wrong
result = d + timedelta(hours=1)
str(result)
# '2022-03-13 02:30:00-05:51'
# Wrong ↑
# 1a. pytz timezone, datetime.timedelta math
import pytz
from datetime import datetime, timedelta
tz = pytz.timezone('America/Chicago')
d = tz.localize(datetime(2022, 3, 13, 1, 30))
result = d + timedelta(hours=1)
str(result)
# '2022-03-13 02:30:00-06:00'
# Wrong ↑
# 2a. dateutil timezone, datetime.timedelta math, method 1
import dateutil.tz
from datetime import datetime, timedelta
tz = dateutil.tz.gettz('America/Chicago')
d = datetime(2022, 3, 13, 1, 30, tzinfo=tz)
result = d + timedelta(hours=1)
str(result)
# '2022-03-13 02:30:00-05:00'
# Wrong ↑
# 3a. dateutil timezone, datetime.timedelta math, method 2
import dateutil.tz
from datetime import datetime, timedelta
tz = dateutil.tz.gettz('America/Chicago')
d = datetime(2022, 3, 13, 1, 30).astimezone(tz)
result = d + timedelta(hours=1)
str(result)
# '2022-03-13 02:30:00-05:00'
# Wrong ↑
# 4a. dateutil timezone, pendulum math
import dateutil.tz
from datetime import datetime
import pendulum
tz = dateutil.tz.gettz('America/Chicago')
d = datetime(2022, 3, 13, 1, 30).astimezone(tz)
result = pendulum.instance(d).add(hours=1)
str(result)
# '2022-03-13T02:30:00-06:00'
# Wrong ↑

Some of those can be rescued by converting the result to a timestamp (seconds since epoch GMT) and back again, and reapplying the timezone - obviously something that really should not have to be done:其中一些可以通过将结果转换为timestamp (自格林威治标准时间以来的秒数)并再次返回并重新应用时区来挽救 - 显然这是不应该做的事情:

# 1b. pytz timezone, datetime.timedelta math
import pytz
from datetime import datetime, timedelta
tz = pytz.timezone('America/Chicago')
d = tz.localize(datetime(2022, 3, 13, 1, 30))
result = d + timedelta(hours=1)
result = datetime.fromtimestamp(result.timestamp()).astimezone(tz)
str(result)
# '2022-03-13 03:30:00-05:00'
# Correct ↑
# 2b. dateutil timezone, datetime.timedelta math, method 1
import dateutil.tz
from datetime import datetime, timedelta
tz = dateutil.tz.gettz('America/Chicago')
d = datetime(2022, 3, 13, 1, 30, tzinfo=tz)
result = d + timedelta(hours=1)
result = datetime.fromtimestamp(result.timestamp()).astimezone(tz)
str(result)
# '2022-03-13 01:30:00-06:00'
# Wrong ↑ (worse!)
# 3b. dateutil timezone, datetime.timedelta math, method 2
import dateutil.tz
from datetime import datetime, timedelta
tz = dateutil.tz.gettz('America/Chicago')
d = datetime(2022, 3, 13, 1, 30).astimezone(tz)
result = d + timedelta(hours=1)
result = datetime.fromtimestamp(result.timestamp()).astimezone(tz)
str(result)
# '2022-03-13 01:30:00-06:00'
# Wrong ↑ (worse!)
# 4b. dateutil timezone, pendulum math
import dateutil.tz
from datetime import datetime
import pendulum
tz = dateutil.tz.gettz('America/Chicago')
d = datetime(2022, 3, 13, 1, 30).astimezone(tz)
result = pendulum.instance(d).add(hours=1)
result = datetime.fromtimestamp(result.timestamp()).astimezone(tz)
str(result)
# '2022-03-13 03:30:00-05:00'
# Correct ↑

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM