[CalendarServer-changes] [3511] CalendarServer/trunk/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Thu Dec 11 11:53:02 PST 2008
Revision: 3511
http://trac.macosforge.org/projects/calendarserver/changeset/3511
Author: cdaboo at apple.com
Date: 2008-12-11 11:53:02 -0800 (Thu, 11 Dec 2008)
Log Message:
-----------
Need to handle the case of DTEND/DURATION normalization as iCal does not support DURATION and always
converts that to DTEND when it writes back an event.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/dateops.py
CalendarServer/trunk/twistedcaldav/ical.py
Added Paths:
-----------
CalendarServer/trunk/twistedcaldav/test/test_dateops.py
Modified: CalendarServer/trunk/twistedcaldav/dateops.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/dateops.py 2008-12-11 19:30:06 UTC (rev 3510)
+++ CalendarServer/trunk/twistedcaldav/dateops.py 2008-12-11 19:53:02 UTC (rev 3511)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2008 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
"""
__all__ = [
+ "normalizeStartEndDuration",
"normalizeToUTC",
"normalizeForIndex",
"floatoffset",
@@ -34,6 +35,21 @@
import datetime
from vobject.icalendar import utc
+def normalizeStartEndDuration(dtstart, dtend=None, duration=None):
+ """
+ Given a DTSTART and DTEND or DURATION (or neither), return a normalized tuple of
+ DTSTART and DTEND.
+ """
+
+ assert dtend is None or duration is None, "Cannot specify both dtend and duration"
+ dtstart = normalizeToUTC(dtstart)
+ if dtend is not None:
+ dtend = normalizeToUTC(dtend)
+ elif duration:
+ dtend = dtstart + duration
+
+ return (dtstart, dtend)
+
def normalizeToUTC(dt):
"""
Normalize a L{datetime.date} or L{datetime.datetime} object to UTC.
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2008-12-11 19:30:06 UTC (rev 3510)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2008-12-11 19:53:02 UTC (rev 3511)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2008 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -34,7 +34,8 @@
from twisted.web2.dav.util import allDataFromStream
from twisted.web2.stream import IStream
-from twistedcaldav.dateops import compareDateTime, normalizeToUTC, timeRangesOverlap
+from twistedcaldav.dateops import compareDateTime, normalizeToUTC, timeRangesOverlap,\
+ normalizeStartEndDuration
from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
from twistedcaldav.instance import InstanceList
from twistedcaldav.log import Logger
@@ -1664,10 +1665,48 @@
if normalize_function:
prop.setValue(normalize_function(prop.value()))
+ # Do datetime normalization
+ self.normalizeDateTimes()
+
# Do to all sub-components too
for component in self.subcomponents():
component.normalizeAll()
+ def normalizeDateTimes(self):
+ """
+ Normalize various datetime properties into UTC and handle DTEND/DURATION variants in such
+ a way that we can compare objects with slight differences.
+
+ Strictly speaking we should not need to do this as clients should not be messing with
+ these properties - i.e. they should roundtrip them. Unfortunately some do...
+ """
+
+ if self.name() == "VEVENT":
+ dtstart = self.getProperty("DTSTART")
+ dtend = self.getProperty("DTEND")
+ duration = self.getProperty("DURATION")
+
+ newdtstart, newdtend = normalizeStartEndDuration(
+ dtstart.value(),
+ dtend.value() if dtend is not None else None,
+ duration.value() if duration is not None else None,
+ )
+
+ dtstart.setValue(newdtstart)
+ try:
+ del dtstart.params()["TZID"]
+ except KeyError:
+ pass
+ if dtend is not None:
+ dtend.setValue(newdtend)
+ try:
+ del dtend.params()["TZID"]
+ except KeyError:
+ pass
+ elif duration is not None:
+ self.removeProperty(duration)
+ self.addProperty(Property("DTEND", newdtend))
+
def normalizePropertyValueLists(self, propname):
"""
Convert properties that have a list of values into single properties, to make it easier
Added: CalendarServer/trunk/twistedcaldav/test/test_dateops.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_dateops.py (rev 0)
+++ CalendarServer/trunk/twistedcaldav/test/test_dateops.py 2008-12-11 19:53:02 UTC (rev 3511)
@@ -0,0 +1,155 @@
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+
+import twistedcaldav.test.util
+from vobject.icalendar import utc, getTzid
+from twistedcaldav.dateops import normalizeStartEndDuration
+from twistedcaldav.timezones import TimezoneCache
+import datetime
+
+#TODO: add tests for all the methods in dateops
+
+class Tests_normalizeStartEndDuration (twistedcaldav.test.util.TestCase):
+ """
+ Test abstract SQL DB class
+ """
+
+ def setUp(self):
+ super(Tests_normalizeStartEndDuration, self).setUp()
+
+ TimezoneCache.create()
+ TimezoneCache.activeCache.loadTimezone("America/New_York")
+
+ def test_invalid(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0, tzinfo=utc)
+ end = datetime.datetime(2008, 1, 1, 1, 0, 0, tzinfo=utc)
+ duration = end - start
+
+ self.assertRaises(AssertionError, normalizeStartEndDuration, start, end, duration)
+
+ def test_start_only_utc(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0, tzinfo=utc)
+
+ newstart, newend = normalizeStartEndDuration(start)
+ self.assertEqual(newstart, start)
+ self.assertTrue(newend is None)
+
+ def test_start_only_float(self):
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0)
+
+ newstart, newend = normalizeStartEndDuration(start)
+ self.assertEqual(newstart, start)
+ self.assertTrue(newend is None)
+
+ def test_start_only_date(self):
+ start = datetime.date(2008, 1, 1)
+
+ newstart, newend = normalizeStartEndDuration(start)
+ self.assertEqual(newstart, start)
+ self.assertTrue(newend is None)
+
+ def test_start_only_tzid(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0, tzinfo=getTzid("America/New_York"))
+ utcstart = datetime.datetime(2008, 1, 1, 5, 0, 0, tzinfo=utc)
+
+ newstart, newend = normalizeStartEndDuration(start)
+ self.assertEqual(newstart, utcstart)
+ self.assertTrue(newend is None)
+
+ def test_start_end_utc(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0, tzinfo=utc)
+ end = datetime.datetime(2008, 1, 1, 1, 0, 0, tzinfo=utc)
+
+ newstart, newend = normalizeStartEndDuration(start, dtend=end)
+ self.assertEqual(newstart, start)
+ self.assertEqual(newend, end)
+
+ def test_start_end_float(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0)
+ end = datetime.datetime(2008, 1, 1, 1, 0, 0)
+
+ newstart, newend = normalizeStartEndDuration(start, dtend=end)
+ self.assertEqual(newstart, start)
+ self.assertEqual(newend, end)
+
+ def test_start_end_date(self):
+
+ start = datetime.date(2008, 1, 1)
+ end = datetime.date(2008, 1, 2)
+
+ newstart, newend = normalizeStartEndDuration(start, dtend=end)
+ self.assertEqual(newstart, start)
+ self.assertEqual(newend, end)
+
+ def test_start_end_tzid(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0, tzinfo=getTzid("America/New_York"))
+ end = datetime.datetime(2008, 1, 1, 1, 0, 0, tzinfo=getTzid("America/New_York"))
+ utcstart = datetime.datetime(2008, 1, 1, 5, 0, 0, tzinfo=utc)
+ utcend = datetime.datetime(2008, 1, 1, 6, 0, 0, tzinfo=utc)
+
+ newstart, newend = normalizeStartEndDuration(start, dtend=end)
+ self.assertEqual(newstart, utcstart)
+ self.assertEqual(newend, utcend)
+
+ def test_start_duration_utc(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0, tzinfo=utc)
+ end = datetime.datetime(2008, 1, 1, 1, 0, 0, tzinfo=utc)
+ duration = end - start
+
+ newstart, newend = normalizeStartEndDuration(start, duration=duration)
+ self.assertEqual(newstart, start)
+ self.assertEqual(newend, end)
+
+ def test_start_duration_float(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0)
+ end = datetime.datetime(2008, 1, 1, 1, 0, 0)
+ duration = end - start
+
+ newstart, newend = normalizeStartEndDuration(start, duration=duration)
+ self.assertEqual(newstart, start)
+ self.assertEqual(newend, end)
+
+ def test_start_duration_date(self):
+
+ start = datetime.date(2008, 1, 1)
+ end = datetime.date(2008, 1, 2)
+ duration = end - start
+
+ newstart, newend = normalizeStartEndDuration(start, duration=duration)
+ self.assertEqual(newstart, start)
+ self.assertEqual(newend, end)
+
+ def test_start_duration_tzid(self):
+
+ start = datetime.datetime(2008, 1, 1, 0, 0, 0, tzinfo=getTzid("America/New_York"))
+ end = datetime.datetime(2008, 1, 1, 1, 0, 0, tzinfo=getTzid("America/New_York"))
+ utcstart = datetime.datetime(2008, 1, 1, 5, 0, 0, tzinfo=utc)
+ utcend = datetime.datetime(2008, 1, 1, 6, 0, 0, tzinfo=utc)
+ duration = end - start
+
+ newstart, newend = normalizeStartEndDuration(start, duration=duration)
+ self.assertEqual(newstart, utcstart)
+ self.assertEqual(newend, utcend)
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20081211/32732cd4/attachment-0001.html>
More information about the calendarserver-changes
mailing list