How to find next day's Unix timestamp for same hour, including DST, in Python?
在Python中,我可以找到当地时间的Unix时间戳,知道时区,就像这样(使用pytz):
1 2 3 4 5 6 7 8 9 10 11 | >>> import datetime as DT >>> import pytz >>> mtl = pytz.timezone('America/Montreal') >>> naive_time3 = DT.datetime.strptime('2013/11/03', '%Y/%m/%d') >>> naive_time3 datetime.datetime(2013, 11, 3, 0, 0) >>> localized_time3 = mtl.localize(naive_time3) >>> localized_time3 datetime.datetime(2013, 11, 3, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>) >>> localized_time3.timestamp() 1383451200.0 |
到现在为止还挺好。
1 2 | $ date -d @1383451200 Sun Nov 3 00:00:00 EDT 2013 |
现在,时钟在11月3日凌晨2点在蒙特利尔调整了一个小时,所以我们当天增加了一小时。这意味着2013/11/03至2013/11/04之间有25小时。这表明:
1 2 3 4 5 6 | >>> naive_time4 = DT.datetime.strptime('2013/11/04', '%Y/%m/%d') >>> localized_time4 = mtl.localize(naive_time4) >>> localized_time4 datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EST-1 day, 19:00:00 STD>) >>> (localized_time4.timestamp() - localized_time3.timestamp()) / 3600 25.0 |
现在,我正在寻找一种从
1 2 3 4 5 | >>> localized_time4td = localized_time3 + DT.timedelta(1) >>> localized_time4td datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>) >>> (localized_time4td.timestamp() - localized_time3.timestamp()) / 3600 24.0 |
我的目的是获取有关每个本地日的Unix时间戳存储的日志条目的信息。当然,如果我在这里使用
换句话说,我正在寻找的功能或方法应该知道何时在Unix时间戳上添加25小时,24小时或23小时,具体取决于DST转换发生的时间。
不使用新包装:
1 2 3 | def add_day(x): d = x.date()+DT.timedelta(1) return mtl.localize(x.replace(year=d.year, month=d.month, day=d.day, tzinfo=None)) |
完整脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import datetime as DT import pytz import calendar mtl = pytz.timezone('America/Montreal') naive_time3 = DT.datetime.strptime('2013/11/03', '%Y/%m/%d') print repr(naive_time3) #datetime.datetime(2013, 11, 3, 0, 0) localized_time3 = mtl.localize(naive_time3) print repr(localized_time3) #datetime.datetime(2013, 11, 3, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>) print calendar.timegm(localized_time3.utctimetuple()) #1383451200.0 def add_day(x): d = x.date()+DT.timedelta(1) return mtl.localize(x.replace(year=d.year, month=d.month, day=d.day, tzinfo=None)) print repr(add_day(localized_time3)) #datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EST-1 day, 19:00:00 STD>) |
(
在本答案的最后,我逐渐提供了几个解决方案,其中包含最强大的解决方案,试图解决以下问题:
- 由DST引起的utc偏移
-
由于与DST无关的原因,本地时区可能具有不同的utc偏移的过去日期。
dateutil 和stdlib解决方案在某些系统上失败,尤其是Windows -
DST期间的模糊时间(不知道
Arrow 是否提供了处理它的接口) - 夏令时期间不存在的时间(相同)
要查找给定时区明天午夜(或其他固定小时)的POSIX时间戳,您可以使用以下代码来获取给定时区的"午夜"UTC时间?
1 2 3 4 5 6 7 8 9 10 | from datetime import datetime, time, timedelta import pytz DAY = timedelta(1) tz = pytz.timezone('America/Montreal') tomorrow = datetime(2013, 11, 3).date() + DAY midnight = tz.localize(datetime.combine(tomorrow, time(0, 0)), is_dst=None) timestamp = (midnight - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds() |
时间戳的显式公式用于在Python 3.3之前支持Python版本。否则
为了避免在除了
1 2 3 4 5 6 7 8 9 10 11 | from datetime import datetime, time, timedelta import pytz DAY = timedelta(1) tz = pytz.timezone('America/Montreal') local_dt = datetime.fromtimestamp(timestamp_from_the_log, tz) tomorrow = local_dt.date() + DAY midnight = tz.localize(datetime.combine(tomorrow, time(0, 0)), is_dst=None) timestamp = (midnight - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds() |
支持其他固定时间(不仅仅是午夜):
1 2 3 | tomorrow = local_dt.replace(tzinfo=None) + DAY # tomorrow, same time dt_plus_day = tz.localize(tomorrow, is_dst=None) timestamp = dt_plus_day.timestamp() # use the explicit formula before Python 3.3 |
如果结果日期不明确或不存在,则
1 2 3 4 5 6 7 8 9 10 11 12 | from datetime import datetime, time, timedelta import pytz DAY = timedelta(1) tz = pytz.timezone('America/Montreal') local_dt = datetime.fromtimestamp(timestamp_from_the_log, tz) tomorrow = local_dt.replace(tzinfo=None) + DAY dt_plus_day = tz.localize(tomorrow, is_dst=local_dt.dst()) dt_plus_day = tz.normalize(dt_plus_day) # to detect non-existent times timestamp = (dt_plus_day - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds() |
这是基于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> # In Spain we changed DST 10/26/2013 >>> import datetime >>> import dateutil.tz >>> # tzlocal gets the timezone of the computer >>> dt1 = datetime.datetime(2013, 10, 26, 14, 00).replace(tzinfo=dateutil.tz.tzlocal()) >>> print dt1 2013-10-26 14:00:00+02:00 >>> dt2 = dt1 + datetime.timedelta(1) >>> print dt2 2013-10-27 14:00:00+01:00 # see if we hace 25 hours of difference >>> import time >>> (time.mktime(dt2.timetuple()) - time.mktime(dt1.timetuple())) / 3600.0 25.0 >>> (float(dt2.strftime('%s')) - float(dt1.strftime('%s'))) / 3600 # the same 25.0 |
(感谢@rdodev将我指向Arrow)。
使用Arrow,此操作变得简单:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> import arrow >>> import datetime as DT >>> lt3 = arrow.get(DT.datetime(2013, 11, 3), 'America/Montreal') >>> lt3 <Arrow [2013-11-03T00:00:00-04:00]> >>> lt4 = arrow.get(DT.datetime(2013, 11, 4), 'America/Montreal') >>> lt4 <Arrow [2013-11-04T00:00:00-05:00]> >>> lt4.timestamp - (lt3.replace(days=1).timestamp) 0 >>> (lt3.replace(days=1).timestamp - lt3.timestamp) / 3600 25.0 |
使用Arrow的