2016-05-05 5 views
1

Я хотел бы рассчитать, сколько часов есть в интервале дат: например, «2014.03.29-30» должно дать 47, из-за летнего сбережения.Разница двух объектов timedelta, с часовыми поясами

Мой метод делает два объекта даты-времени, в примере ниже:

datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>) 
datetime.datetime(2014, 3, 30, 23, 59, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>) 
return (date2-date1) + timedelta(minutes=1) 

Однако, это дает «2 дня, 0:00:00», которая не является правильным. Как я могу создать объект timedelta, который учитывает часовые пояса и dst? Кроме того, если есть более простое решение для всей проблемы, я открыт для этого.

Спасибо!

ответ

2

До 1901-12-13 20:45:52 UTC, часовой пояс 'Europe/Budapest' был LMT + 1: 16: 00 STD. В настоящее время, с 2016-05-05, часовой пояс 'Europe/Budapest' является CET + 2: 00: 00 DST.

При использовании pytz-х localize method, то pytz будет выбрать часовой пояс (utcoffset и dstoffset) для 'Europe/Budapest', который подходит для данного наивным DateTime:

import datetime as DT 
import pytz 

tzone = pytz.timezone('Europe/Budapest') 
date1 = tzone.localize(DT.datetime(2014, 3, 29, 0, 0), is_dst=None) 
# datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' CET+1:00:00 STD>) 

В отличие от этого, если вы поставляете tzinfo=tzone непосредственно datetime.datetime, как в:

wrong_date1 = datetime.datetime(2014, 3, 29, 0, 0, tzinfo=tzone) 
# datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>) 

то datetime.datetimeнеправильно выбирает самую первую временную зону ассоциированных с 'Europe/Budapest'независимо от того, был ли это часовой пояс, действующий на 2014-3-29 гг..

Таким образом, при использовании pytz, всегда используйте tzone.localize сделать наивные DateTimes часовой пояс, известно: (. Или часовой пояс, который все дни одинаковы по всей своей истории)

import datetime as DT 
import pytz 
tzone = pytz.timezone('Europe/Budapest') 
date1 = tzone.localize(DT.datetime(2014, 3, 29, 0, 0), is_dst=None) 
date2 = tzone.localize(DT.datetime(2014, 3, 30, 23, 59), is_dst=None) 
print(((date2-date1) + DT.timedelta(minutes=1)).total_seconds()/3600.) 
# 47.0 

Do not use tzinfo=tzone если tzone не pytz.utc


Откуда взялась дата 1901-12-13 20:45:52 UTC?

Вы можете взглянуть на время UTC на переход pytz TimeZone (и связанной информации перехода), используя свои tzone._utc_transition_times и tzone._transition_info личные атрибуты:

In [43]: [(utcdate, utcoffset, dstoffset, tzabbrev) for utcdate, (utcoffset, dstoffset, tzabbrev) in zip(tzone._utc_transition_times, tzone._transition_info)][:2] 
Out[43]: 
[(datetime.datetime(1, 1, 1, 0, 0), 
    datetime.timedelta(0, 4560), 
    datetime.timedelta(0), 
    'LMT'), 
(datetime.datetime(1901, 12, 13, 20, 45, 52), 
    datetime.timedelta(0, 3600), 
    datetime.timedelta(0), 
    'CET')] 

Это показывает, что с даты 1-1-1 UTC в 1901-12-13 20:45:52 UTC часовом поясе аббревиатура была LMT и utcoffset составляло 4560 секунд, что равно 1 час и 16 минут:

In [47]: print(DT.timedelta(0, 4560)) 
1:16:00 

Следовательно, первый t imezone, связанный с 'Europe/Budapest', составляет LMT+1:16:00 STD.

+0

Спасибо! Последнее: что делает 'is_dst = None'? Я случайно пропустил его, но он работает так, как должен. – Rolf

+2

'is_dst = None' сообщает' tzone.localize', чтобы поднять 'AmbiguousTimeError' для неоднозначных времен, когда время перехода на летнее время заканчивается -« падение назад »вызывает одно и то же наивное время, которое происходит дважды.В противном случае он делает то, что подходит. Он используется из «изобилия предостережения», как хорошая общая привычка, хотя он здесь не действует. По умолчанию 'is_dst = False', что означает, что' tzone.localize' будет разрешать неоднозначные времена * предполагая *, что наивное datetime относится к дате времени, когда переход на летнее время не действует. – unutbu

+0

Я понимаю, спасибо. – Rolf