Django ical与pytz的Vobject问题



我正在使用vobject在Django中创建一个ical事件。我在使用较低级别的代码时遇到问题。看起来ical正试图用obj.add(TimezoneComponent(tzinfo=getTzid(tzid)))抢占一个时区。但后来我从pytz那里得到了raise NonExistentTimeError(dt)。有什么建议吗?当我在变量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

从模型中,日期时间字段:

date_due = models.DateTimeField()

更新:

发现我必须放置:

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

它起了作用。

简短回答:vobject(截至0.9.2)与pytz不兼容。因此,请确保vobject iCalendar中的每个日期时间都已转换为UTC,然后再尝试使用类似.astimezone(pytz.utc)的方法对其进行序列化。

(这是每个dtstart、dtend、dtstamp、created、last-modified,也许还有我忘记的其他一些vevent字段。)

长答案:vobject试图为非UTC日期时间做正确的事情,但遇到了pytz问题。";正确的事情;来自RFC 5545,它指定iCalendar:

  1. 使用DATE-TIME Form#3表示日期时间";具有本地时间和时区参考的日期";。这可能类似于DTSTART;TZID=America/New_York:20160714T133000——请注意活动时区的TZID。

  2. 为活动中使用的每个唯一TZID向iCalendar添加VTIMEZONE块。这是该时区的完整定义:如何计算出该时区与UTC之间可能出现的任何日期时间的偏移量,包括夏令时规则。(RFC 5545没有指定任何特定的时区名称,所以你必须在iCalendar本身中包含时区定义。vobject会自动为你做这件事。)

为了找出时区转换规则,vobject搜索";所有时间";(默认年份2000-2030),查找时区与UTC偏移量的变化。这就是问题所在,因为vobject代码无法处理pytz的无效时间错误。

2000年4月2日凌晨2点是2000-2030年之间的第一次夏令时转换,这就是为什么你在那段时间会遇到错误(尽管你在自己的代码中没有使用它)。

选项:

  • 如果您不想要一天中的特定时间(如原始问题中所述),请使用date而不是datetime。日期没有时区,所以这些都不适用。(vobject处理日期也很好。)
  • 将所有datetime转换为UTC的可识别日期时间。UTC不需要VTIMEZONE定义
  • 使用dateutil时区而不是pytz。例如,from dateutil import tz; ... tzinfo=tz.gettz('America/Los_Angeles')。由于dateutil是vobject依赖项,我认为这就是vobject的VTIMEZONE生成器所针对的格式。(但尚未进行广泛测试。此外,gettz需要在您的机器上安装tzdb文件,因此不完全可移植。)
  • 将您自己的VTIMEZONE定义添加到您使用的每个TZID的iCalendar中,这样可以避免vobject中出现问题的自动时区生成代码。(未经测试。在一般情况下,正确处理很复杂。)
  • 提交PR以修复vobject与pytz一起使用

最新更新