如何找到时区的下一个早上7点 [英] How do I find the next 7am in a timezone
问题描述
current_datetime = datetime.now(tz)
next_hour = datetime(current_datetime.year, current_datetime.month, current_datetime.day, 7, 0, 0, 0, tz)
timedelta_until_next_hour = next_hour - current_datetime
if timedelta_until_next_hour.total_seconds() < 0:
timedelta_until_next_hour += timedelta(days=1)
return timedelta_until_next_hour.total_seconds()
我正在尝试查找下一次是本地时区的上午7点,并返回直到该时间的秒数。
I'm trying to find the next time it's 7am for a local timezone and return the number of seconds until that.
我有一些夏令时时间问题。例如:美国/纽约
current_datetime
的utcoffset为-4小时
而 next_hour
的偏移量为-5小时,因此两者的减法为一个小时
I'm having some daylight savings time issues. For Example: America/New_York
current_datetime
has a utcoffset of -4 hours
Whereas next_hour
has an offset of -5 hours, so the subtraction of the two is off by an hour
推荐答案
查找下一个上午7点
使用 python-dateutil
的 relativedelta
模块:
from dateutil.relativedelta import relativedelta
def next_7am(dt):
relative_days = (dt.hour >= 7)
absolute_kwargs = dict(hour=7, minute=0, second=0, microsecond=0)
return dt + relativedelta(days=relative_days, **absolute_kwargs)
它的工作方式是 relativedelta
需要绝对参数(以单数表示,例如 month
, year
, day
)和 relative 参数(以复数形式表示,例如个月
,年
,天
)。如果在 datetime
中添加 relativedelta
对象,它将替换绝对值。 datetime
,然后添加相对
值,因此我在上面所做的是指定 relative_days
如果已经是早上7点,则应该是 1
,否则应该是0,并且绝对参数说将时间替换为7 AM。将其添加到您的日期时间,它将为您提供下一个上午7点。
The way it works is that relativedelta
takes absolute arguments (denoted by being in the singular, e.g. month
, year
, day
) and relative arguments (denoted by being in the plural, e.g. months
, years
, days
). If you add a relativedelta
object to a datetime
, it will replace absolute values in the datetime
, then add the relative
values, so what I've done above is specify that relative_days
should be 1
if it's already 7am, otherwise it should be 0, and the absolute arguments say "replace the time with 7 AM". Add that to your datetime and it will give you the next 7am.
下一个步骤取决于您的时区使用什么。如果您使用的是 dateutil
时区,则可以使用上面定义的函数:
The next step depends on what you are using for your time zone. If you are using a dateutil
time zone, then you can just use the function defined above:
dt_next_7am = next_7am(dt)
如果您使用的是 pytz
时区,您应该将其剥离并作为原始日期时间进行计算,然后重新定位时区,如下所示:
If you are using a pytz
timezone, you should strip it off and do the calculation as a naive date-time, then re-localize the time zone, as below:
dt_next_7am = tz.localize(next_7am(dt.replace(tzinfo=None)))
如果要获取两次之间的绝对小时数,则应使用UTC进行算术运算。
If you want to get the absolute number of hours between those two times, you should do the arithmetic in UTC:
time_between = dt_next_7am.astimezone(tz=UTC) - dt.astimezone(tz=UTC)
其中 UTC
被定义为 dateutil.tz.tzutc()
或 pytz.UTC
或等价货币。
Where UTC
has been defined as either dateutil.tz.tzutc()
or pytz.UTC
or equivalent.
这是使用 dateutil
的示例(结果在注释中):
Here is an example using dateutil
(with the result in the comment):
from datetime import datetime
from dateutil.tz import gettz, tzutc
LA = gettz('America/Los_Angeles')
dt = datetime(2011, 11, 5, 12, 30, tzinfo=LA)
dt7 = next_7am(dt)
print(dt7.astimezone(tzutc()) - dt.astimezone(tzutc())) # 19:30:00
以及显示错误和正确方法的示例为此,请使用 pytz
:
And an example showing the wrong and right way to do this with pytz
:
from datetime import datetime
import pytz
LA = pytz.timezone('America/Los_Angeles')
UTC = pytz.UTC
dt = LA.localize(datetime(2011, 11, 5, 12, 30))
dt7_bad = next_7am(dt) # pytz won't like this
dt7_good = LA.localize(next_7am(dt.replace(tzinfo=None)))
dt_utc = dt.astimezone(pytz.UTC)
print(dt7_bad.astimezone(pytz.UTC) - dt_utc) # 18:30:00 (Wrong)
print(dt7_good.astimezone(pytz.UTC) - dt_utc) # 19:30:00 (Right)
模棱两可/不存在
如果以下列表(截至2016年4月)处理某些区域中的某些日期,尤其是那些会导致时间不明确的日期:
Ambiguous / Non-existent 7 AM
If you are dealing with certain dates in certain zones, specifically those that would result in an ambiguous time are on the following list (as of April 2016):
1901-12-13 07:00:00 (/Pacific/Fakaofo)
1901-12-14 07:00:00 (/Asia/Kamchatka)
1901-12-14 07:00:00 (/Asia/Ust-Nera)
1901-12-14 07:00:00 (/Pacific/Bougainville)
1901-12-14 07:00:00 (/Pacific/Kosrae)
1901-12-14 07:00:00 (/Pacific/Majuro)
1917-03-25 07:00:00 (/Antarctica/Macquarie)
1918-03-31 07:00:00 (/EST5EDT)
1919-03-31 07:00:00 (/Antarctica/Macquarie)
1952-01-13 07:00:00 (/Antarctica/DumontDUrville)
1954-02-13 07:00:00 (/Antarctica/Mawson)
1957-01-13 07:00:00 (/Antarctica/Davis)
1969-01-01 07:00:00 (/Antarctica/Casey)
1969-02-01 07:00:00 (/Antarctica/Davis)
1969-09-29 07:00:00 (/Kwajalein)
1969-09-29 07:00:00 (/Pacific/Kwajalein)
1979-09-30 07:00:00 (/Pacific/Enderbury)
1979-09-30 07:00:00 (/Pacific/Kiritimati)
2009-10-18 07:00:00 (/Antarctica/Casey)
2011-09-23 07:00:00 (/Pacific/Apia)
2011-10-28 07:00:00 (/Antarctica/Casey)
然后得出的7AM值将是模棱两可或不存在。如果要处理这些极端情况,请参阅此答案。可能值得注意的是,在实施 PEP495 之后,处理的模棱两可
Then the resulting 7AM value will be either ambiguous or non-existent. If you want to handle these edge cases, see this answer. It is probably worth noting that after PEP495 has been implemented, dealing with ambiguous times will probably be handled slightly differently.
使用 python-dateutil
的 pytz
区域的重复规则和方法的> rrule 模块(请注意,该模块将与非 pytz一起使用
区域,但无法正确解决模糊/不存在的时间):
An alternative implementation using python-dateutil
's rrule
module for generating recurrence rules and approach with pytz
zones is below (note that this will work with non-pytz
zones, but it will not resolve ambiguious/non-existent times properly):
from datetime import datetime
from dateutil import rrule
import pytz
def next_real_7am(dt):
tzi = dt.tzinfo
dt_naive = dt.replace(tzinfo=None)
rr = rrule.rrule(freq=rrule.DAILY, byhour=7, dtstart=dt_naive)
for ndt in rr:
localize = getattr(tzi, 'localize', None)
if tzi is not None and localize is not None:
try:
ndt = localize(ndt, is_dst=None)
except pytz.AmbiguousTimeError:
return min([localize(ndt, is_dst=True),
localize(ndt, is_dst=False)])
except pytz.NonExistentTimeError:
continue
else:
ndt = ndt.replace(tzinfo=tzi)
return ndt
KWA = pytz.timezone('Pacific/Kwajalein')
dtstart = KWA.localize(datetime(1969, 9, 29, 18))
dt7 = next_real_7am(dtstart)
print(dt7.tzname()) # Should be MHT, before the transition
dtstart = KWA.localize(datetime(1993, 8, 19, 18)) # There was no 8/20 in this zone
dt7 = next_real_7am(dtstart)
print(dt7) # Should be 1993-8-21 07:00:00
这篇关于如何找到时区的下一个早上7点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!