2014-01-15 8 views
1

Я использую vobject для создания ical события в Django. У меня проблемы с кодом нижнего уровня. Похоже, что ical пытается захватить часовой пояс с obj.add(TimezoneComponent(tzinfo=getTzid(tzid))). Но затем я получаю raise NonExistentTimeError(dt) от pytz. Любые предложения о том, что делать? Год, месяц, день отображаются правильно, когда я просматривал их с помощью инструкции print для переменной start1.Django ical with Vobject issue with pytz

File "/home/git/chrono/chrono/requests_app/views.py", line 110, in form_valid 
    ics_form = create_ics(data) 
    File "/home/git/chrono/chrono/requests_app/views.py", line 126, in create_ics 
    response = HttpResponse(cal.serialize(), content_type='text/calendar') 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/base.py", line 186, in serialize 
    return behavior.serialize(self, buf, lineLength, validate) 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/behavior.py", line 147, in serialize 
    cls.generateImplicitParameters(obj) 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/icalendar.py", line 853, in generateImplicitParameters 
    obj.add(TimezoneComponent(tzinfo=getTzid(tzid))) 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/icalendar.py", line 75, in __init__ 
    self.tzinfo = tzinfo 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/base.py", line 468, in __setattr__ 
    prop.fset(self, value) 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/icalendar.py", line 145, in settzinfo 
    transition = getTransition(transitionTo, year, tzinfo) 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/icalendar.py", line 1856, in getTransition 
    uncorrected = firstTransition(generateDates(year, month, day), test) 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/icalendar.py", line 1816, in firstTransition 
    if not test(dt): 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/vobject/icalendar.py", line 1843, in test 
    def test(dt): return tzinfo.dst(dt) != zeroDelta 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/pytz/tzinfo.py", line 445, in dst 
    dt = self.localize(dt, is_dst) 
    File "/home/one/.virtualenvs/chronos/local/lib/python2.7/site-packages/pytz/tzinfo.py", line 327, in localize 
    raise NonExistentTimeError(dt) 
NonExistentTimeError: 2000-04-02 02:00:00 



def create_ics(data): 
    start1 = data['date_due'] 
    print start1.day 
    start2 = datetime.datetime(start1.year, start1.month, start1.day) 
    start3 = data['action'] 
    cal = vobject.iCalendar() 
    cal.add('method').value = 'PUBLISH' 
    vevent = cal.add('vevent') 
    vevent.add('dtstart').value = start1 
    vevent.add('dtend').value = start2 
    vevent.add('dtstamp').value = datetime.datetime.now() 
    vevent.add('summary').value = data['action'].name 
    response = HttpResponse(cal.serialize(), content_type='text/calendar') 
    response['Filename'] = 'filename.ics' 
    response['Content-Disposition'] = 'attachment; filename=filename.ics' 
    return response 

из моделей, поле даты и времени:

date_due = models.DateTimeField() 

UPDATE:

Найдено мне пришлось ставить:

>>> utc = vobject.icalendar.utc 
>>> start = cal.vevent.add('dtstart') 
>>> start.value = datetime.datetime(2006, 2, 16, tzinfo = utc) 

в него, который работал.

+0

Я попытался добавить этот код, но у меня все тот же крах. Есть ли у кого-нибудь идея, откуда приходит дата 2000 года, или почему добавление другого события привело к сбою в работе @dman? –

+0

Это было долгое время, поэтому многие вещи могли измениться в мире django :) – dman

+0

Я не думаю, что эта ошибка действительно имеет отношение к Django. В моем случае я обнаружил, что я вызываю 'pytz.timezone.normalize()' излишне, прежде чем перейти к iCalendar. Я удалил звонок, и авария исчезла. –

ответ

2

Короткий ответ: vobject не является (на 0.9.2) совместимым с pytz. Поэтому убедитесь, что каждый datetime в вашем vobject iCalendar был конвертирован в UTC, прежде чем пытаться сериализовать его, используя что-то вроде .astimezone(pytz.utc).

(Это каждый dtstart, dtend, dtstamp, созданный, последнего изменения, и, возможно, некоторые другие поля VEVENT я забыл.)

Длинный ответ: vobject пытается сделать правильную вещь для не-UTC datetimes, но сталкивается с проблемами с pytz. «Правильно» происходит от RFC 5545, который определяет Анонсы:

  1. Представляют DateTime, используя DATE-TIME Form #3 «дату с местным временем и ссылки часового пояса». Это может быть что-то вроде DTSTART;TZID=America/New_York:20160714T133000 - обратите внимание на TZID для часового пояса вашего мероприятия.

  2. Добавить блок VTIMEZONE в свой iCalendar для каждого уникального TZID, используемого в ваших мероприятиях. Это полное определение этого часового пояса: как определить смещение часового пояса от UTC для любого времени, которое может появиться, включая правила летнего времени. (RFC 5545 doesn't specify какие-либо конкретные имена часовых поясов, поэтому вы должны включить определения часового пояса в самых Анонсах. Vobject делает это для вас автоматически.)

Чтобы выяснить правила преобразования часовых поясов, vobject searches through "all time" (по умолчанию лет 2000-2030), ища изменения смещения часового пояса от UTC. И здесь все идет не так, потому что код vobject не обрабатывает неверные ошибки времени pytz.

2:00 2 апреля 2000 г. - первый переход на летнее время между 2000-2030 годами, поэтому вы получаете сообщение об ошибке (хотя вы не использовали его нигде в своем собственном коде).

Опции:

  • Использование date вместо datetime, если вы не хотите, в определенное время суток (как в оригинале вопрос). Даты не имеют временных интервалов, поэтому все это не относится. (И vobject обрабатывает даты только отлично.)
  • Преобразуйте все datetime в известные даты в UTC. UTC не требует определения VTIMEZONE.
  • Использовать dateutil timezones вместо pytz. Например, from dateutil import tz; ... tzinfo=tz.gettz('America/Los_Angeles'). Поскольку dateutil является зависимостью vobject, I думаю, это формат VOBMETZON VOBESTON, разработанный против. (Но не тестировались экстенсивно. Кроме того, gettz требует, чтобы на вашем компьютере были установлены файлы tzdb, поэтому не полностью переносимы.)
  • Добавьте свои собственные определения VTIMEZONE в iCalendar для каждого TZID, который вы используете, что должно избегать проблемного авто - код поколения времени в vobject. (Непроверено и сложно получить право в общем случае.)
  • Отправить aPR to fix vobject to work with pytz.