1

vobject を使用して、Django で ical イベントを作成しています。下位レベルのコードに問題があります。ical が でタイムゾーンを取得しようとしているようobj.add(TimezoneComponent(tzinfo=getTzid(tzid)))です。しかし、私raise NonExistentTimeError(dt)はpytzから取得します。何をすべきかについて何か提案はありますか?年、月、日は、変数 start1 の print ステートメントで表示すると正しく表示されます。

 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

モデルから、datetime フィールド:

date_due = models.DateTimeField()

アップデート:

配置する必要があることがわかりました:

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

それに、うまくいきました。

4

1 に答える 1

2

簡単な答え: vobject は (0.9.2 の時点で) pytz と互換性がありません。そのため、vobject iCalendar のすべての.astimezone(pytz.utc)日時が、シリアル化を試みる前に UTC に変換されていることを確認してください。

(これは、すべてのdtstart、dtend、dtstamp、created、last-modified、および忘れていたその他の vevent フィールドです。)

長い答え: vobject は非 UTC 日時に対して正しいことをしようとしますが、pytz で問題が発生します。「正しいこと」は、iCalendar を指定するRFC 5545から来ています。

  1. DATE-TIME フォーム #3「現地時間とタイムゾーン参照を含む日付」を使用して日時を表します。それは次のようなものかもしれませんDTSTART;TZID=America/New_York:20160714T133000-- イベントのタイムゾーンの TZID に注意してください。

  2. イベントで使用される一意の TZID ごとにVTIMEZONEブロックを iCalendar に追加します。これは、そのタイムゾーンの完全な定義です。夏時間のルールを含め、表示される可能性のある日時について、そのタイムゾーンの UTC からのオフセットを計算する方法です。(RFC 5545では特定のタイムゾーン名が指定されていないため、iCalendar 自体にタイムゾーンの定義を含める必要があります。vobject が自動的にこれを行います。)

タイムゾーン変換規則を理解するために、vobjectは「すべての時間」 (デフォルトでは 2000 年から 2030 年) を検索し、UTC からのタイムゾーンのオフセットの変化を探します。vobject コードは pytz の無効な時間エラーを処理しないため、ここで問題が発生します。

2000 年 4 月 2 日午前 2:00 は、2000 年から 2030 年までの最初の DST 移行です。そのため、その時間についてエラーが発生します (コードのどこにも使用していませんが)。

オプション:

  • 特定の時刻が必要ない場合はdate代わりに使用します(元の質問のように)。datetime日付にはタイムゾーンがないため、これは当てはまりません。(そして、vobject は日付を問題なく処理します。)
  • datetimeすべてを UTC の対応する日時に変換します。UTC は VTIMEZONE 定義を必要としません。
  • pytzの代わりにdateutil タイムゾーンを使用します。例: from dateutil import tz; ... tzinfo=tz.gettz('America/Los_Angeles'). dateutil は vobject の依存関係であるため、これは vobject の VTIMEZONE ジェネレーターが設計されている形式であると思います。(ただし、十分なテストは行っていません。また、gettz はマシンに tzdb ファイルをインストールする必要があるため、完全に移植できるわけではありません。)
  • 使用するすべての TZID について、独自の VTIMEZONE 定義を iCalendar に追加します。これにより、vobject での問題のある自動タイムゾーン生成コードを回避できます。(テストされていません。一般的なケースで正しく理解するのは複雑です。)
  • pytz で動作するように vobject を修正するために PR を提出してください。
于 2016-05-26T23:07:09.043 に答える