[CalendarServer-changes] [14933] CalendarServer/trunk/txdav

source_changes at macosforge.org source_changes at macosforge.org
Tue Jun 30 12:35:01 PDT 2015


Revision: 14933
          http://trac.calendarserver.org//changeset/14933
Author:   cdaboo at apple.com
Date:     2015-06-30 12:35:01 -0700 (Tue, 30 Jun 2015)
Log Message:
-----------
Add a test to verify a group removed attendee gets a cancel message. Use mix-in class for tests that need to do iCalendar date-time substitutions.

Modified Paths:
--------------
    CalendarServer/trunk/txdav/caldav/datastore/test/test_queue_scheduling.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
    CalendarServer/trunk/txdav/caldav/datastore/test/util.py
    CalendarServer/trunk/txdav/common/datastore/test/util.py
    CalendarServer/trunk/txdav/who/test/test_group_attendees.py

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_queue_scheduling.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_queue_scheduling.py	2015-06-30 18:57:02 UTC (rev 14932)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_queue_scheduling.py	2015-06-30 19:35:01 UTC (rev 14933)
@@ -19,11 +19,10 @@
 from twext.python.clsprop import classproperty
 from twistedcaldav.config import config
 from txdav.caldav.datastore.scheduling.work import ScheduleWorkMixin
-from txdav.caldav.datastore.test.util import CommonStoreTests
-from txdav.common.datastore.test.util import componentUpdate
-from twistedcaldav.ical import normalize_iCalStr
+from txdav.caldav.datastore.test.util import CommonStoreTests, \
+    DateTimeSubstitutionsMixin
 
-class BaseQueueSchedulingTests(CommonStoreTests):
+class BaseQueueSchedulingTests(CommonStoreTests, DateTimeSubstitutionsMixin):
 
     """
     Test store-based calendar sharing.
@@ -41,7 +40,9 @@
         self.patch(config.Scheduling.Options.WorkQueues, "AttendeeRefreshBatchDelaySeconds", 1)
         self.patch(config.Scheduling.Options.WorkQueues, "AttendeeRefreshBatchIntervalSeconds", 1)
 
+        self.setupDateTimeValues()
 
+
     @classproperty(cache=False)
     def requirements(cls): #@NoSelf
         return {
@@ -87,7 +88,7 @@
         self.assertEqual(len(objs), 1)
 
         caldata = yield objs[0].componentForUser()
-        self.assertEqual(normalize_iCalStr(caldata), normalize_iCalStr(componentUpdate(data)))
+        self.assertEqualCalendarData(caldata, data.format(**self.dtsubs))
 
 
 
@@ -104,7 +105,7 @@
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;PARTSTAT=ACCEPTED:mailto:user01 at example.com
 ATTENDEE:mailto:user02 at example.com
@@ -120,7 +121,7 @@
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user02
@@ -137,7 +138,7 @@
 METHOD:REQUEST
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
@@ -153,7 +154,7 @@
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
@@ -170,7 +171,7 @@
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user02
@@ -186,7 +187,7 @@
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;PARTSTAT=ACCEPTED;SCHEDULE-STATUS=2.0:urn:x-uid:user02
@@ -203,7 +204,7 @@
 METHOD:REPLY
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user02
 DTSTAMP:20051222T210507Z
@@ -219,7 +220,7 @@
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
 UID:12345-67890
-DTSTART:{now}T000000Z
+DTSTART:{nowDate}T000000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user02
@@ -232,7 +233,7 @@
 
         waitForWork = ScheduleWorkMixin.allDone()
         calendar = yield self.calendarUnderTest(home="user01", name="calendar")
-        yield calendar.createCalendarObjectWithName("data1.ics", componentUpdate(data1))
+        yield calendar.createCalendarObjectWithName("data1.ics", data1.format(**self.dtsubs))
         yield self.commit()
 
         yield waitForWork
@@ -244,7 +245,7 @@
 
         waitForWork = ScheduleWorkMixin.allDone()
         cobj = yield self._getOneResource("user02", "calendar")
-        yield cobj.setComponent(componentUpdate(data5))
+        yield cobj.setComponent(data5.format(**self.dtsubs))
         yield self.commit()
 
         yield waitForWork

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2015-06-30 18:57:02 UTC (rev 14932)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2015-06-30 19:35:01 UTC (rev 14933)
@@ -60,6 +60,7 @@
 from txdav.caldav.datastore.test.common import CommonTests as CalendarCommonTests, \
     test_event_text, cal1Root
 from txdav.caldav.datastore.test.test_file import setUpCalendarStore
+from txdav.caldav.datastore.test.util import DateTimeSubstitutionsMixin
 from txdav.common.datastore.test.util import populateCalendarsFrom, \
     CommonCommonTests, updateToCurrentYear
 from txdav.caldav.datastore.util import _migrateCalendar, migrateHome
@@ -3162,7 +3163,7 @@
 
 
 
-class CalendarObjectSplitting(CommonCommonTests, unittest.TestCase):
+class CalendarObjectSplitting(CommonCommonTests, DateTimeSubstitutionsMixin, unittest.TestCase):
     """
     CalendarObject splitting tests
     """
@@ -3179,71 +3180,8 @@
             self.assertNotEqual(home_uid, None)
         yield self.commit()
 
-        self.subs = {}
+        self.setupDateTimeValues()
 
-        self.now = DateTime.getNowUTC()
-        self.now.setHHMMSS(0, 0, 0)
-        self.nowDate = self.now.duplicate()
-        self.nowDate.setDateOnly(True)
-        self.nowFloating = self.now.duplicate()
-        self.nowFloating.setTimezoneID(None)
-
-        self.subs["now"] = self.now
-        self.subs["nowDate"] = self.nowDate
-        self.subs["nowFloating"] = self.nowFloating
-
-        for i in range(30):
-            attrname = "now_back%s" % (i + 1,)
-            setattr(self, attrname, self.now.duplicate())
-            getattr(self, attrname).offsetDay(-(i + 1))
-            self.subs[attrname] = getattr(self, attrname)
-
-            attrname_12h = "now_back%s_12h" % (i + 1,)
-            setattr(self, attrname_12h, getattr(self, attrname).duplicate())
-            getattr(self, attrname_12h).offsetHours(12)
-            self.subs[attrname_12h] = getattr(self, attrname_12h)
-
-            attrname_1 = "now_back%s_1" % (i + 1,)
-            setattr(self, attrname_1, getattr(self, attrname).duplicate())
-            getattr(self, attrname_1).offsetSeconds(-1)
-            self.subs[attrname_1] = getattr(self, attrname_1)
-
-            attrname = "nowDate_back%s" % (i + 1,)
-            setattr(self, attrname, self.nowDate.duplicate())
-            getattr(self, attrname).offsetDay(-(i + 1))
-            self.subs[attrname] = getattr(self, attrname)
-
-            attrname = "nowFloating_back%s" % (i + 1,)
-            setattr(self, attrname, self.nowFloating.duplicate())
-            getattr(self, attrname).offsetDay(-(i + 1))
-            self.subs[attrname] = getattr(self, attrname)
-
-            attrname_1 = "nowFloating_back%s_1" % (i + 1,)
-            setattr(self, attrname_1, getattr(self, attrname).duplicate())
-            getattr(self, attrname_1).offsetSeconds(-1)
-            self.subs[attrname_1] = getattr(self, attrname_1)
-
-        for i in range(30):
-            attrname = "now_fwd%s" % (i + 1,)
-            setattr(self, attrname, self.now.duplicate())
-            getattr(self, attrname).offsetDay(i + 1)
-            self.subs[attrname] = getattr(self, attrname)
-
-            attrname_12h = "now_fwd%s_12h" % (i + 1,)
-            setattr(self, attrname_12h, getattr(self, attrname).duplicate())
-            getattr(self, attrname_12h).offsetHours(12)
-            self.subs[attrname_12h] = getattr(self, attrname_12h)
-
-            attrname = "nowDate_fwd%s" % (i + 1,)
-            setattr(self, attrname, self.nowDate.duplicate())
-            getattr(self, attrname).offsetDay(i + 1)
-            self.subs[attrname] = getattr(self, attrname)
-
-            attrname = "nowFloating_fwd%s" % (i + 1,)
-            setattr(self, attrname, self.nowFloating.duplicate())
-            getattr(self, attrname).offsetDay(i + 1)
-            self.subs[attrname] = getattr(self, attrname)
-
         self.patch(config, "MaxAllowedInstances", 500)
 
 
@@ -3452,7 +3390,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -3476,7 +3414,7 @@
         ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails("user01")
 
         title = "temp"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = pastUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -3665,7 +3603,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -3689,7 +3627,7 @@
         ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails("user01")
 
         title = "temp"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = pastUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s %s" % (title, diff_iCalStrs(ical_future, data_future % relsubs)))
@@ -3874,7 +3812,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -3898,7 +3836,7 @@
         ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails("user01")
 
         title = "temp"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = pastUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s %s" % (title, diff_iCalStrs(ical_future, data_future % relsubs)))
@@ -4324,7 +4262,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertTrue(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -4353,7 +4291,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = pastUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -4486,7 +4424,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertTrue(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -4708,7 +4646,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -4720,16 +4658,16 @@
         cobj = cobjs[0]
         cname2 = cobj.name()
         ical = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(ical), normalize_iCalStr(data_2) % self.subs, "Failed 2")
-        yield cobj.setComponent(Component.fromString(data_2_update % self.subs))
+        self.assertEqual(normalize_iCalStr(ical), normalize_iCalStr(data_2) % self.dtsubs, "Failed 2")
+        yield cobj.setComponent(Component.fromString(data_2_update % self.dtsubs))
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         ical = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(ical), normalize_iCalStr(data_1) % self.subs, "Failed 2")
+        self.assertEqual(normalize_iCalStr(ical), normalize_iCalStr(data_1) % self.dtsubs, "Failed 2")
         cobj = yield self.calendarObjectUnderTest(name=cname2, calendar_name="calendar", home="user02")
         ical = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(ical), normalize_iCalStr(data_2_changed) % self.subs, "Failed 2")
+        self.assertEqual(normalize_iCalStr(ical), normalize_iCalStr(data_2_changed) % self.dtsubs, "Failed 2")
         yield self.commit()
 
 
@@ -4794,7 +4732,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -5090,7 +5028,7 @@
 """
 
         # Create initial non-split event
-        cobj = yield calendar.createCalendarObjectWithName("data1.ics", Component.fromString(data_1 % self.subs))
+        cobj = yield calendar.createCalendarObjectWithName("data1.ics", Component.fromString(data_1 % self.dtsubs))
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
 
@@ -5107,7 +5045,7 @@
         self.assertEqual(attachment.parameterValue("MANAGED-ID"), mid)
         self.assertEqual(attachment.value(), location)
 
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["mid"] = mid
         relsubs["att_uri"] = location
         relsubs["dtstamp"] = str(ical.masterComponent().propertyValue("DTSTAMP"))
@@ -5447,7 +5385,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -5459,7 +5397,7 @@
         cobj = yield self.calendarObjectUnderTest(name="data.ics", calendar_name="calendar", home="user01")
         processor.recipient_calendar_resource = cobj
         processor.recipient_calendar = (yield cobj.componentForUser("user01"))
-        processor.message = Component.fromString(itip1 % self.subs)
+        processor.message = Component.fromString(itip1 % self.dtsubs)
         processor.originator = RemoteCalendarUser("mailto:cuser01 at example.org")
         processor.recipient = LocalCalendarUser("urn:x-uid:user01", None)
         processor.method = "REQUEST"
@@ -5470,7 +5408,7 @@
         yield self.commit()
 
         new_names = []
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
 
         @inlineCallbacks
         def _verify_state():
@@ -5599,7 +5537,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -5611,7 +5549,7 @@
         cobj = yield self.calendarObjectUnderTest(name="data.ics", calendar_name="calendar", home="user01")
         processor.recipient_calendar_resource = cobj
         processor.recipient_calendar = (yield cobj.componentForUser("user01"))
-        processor.message = Component.fromString(itip1 % self.subs)
+        processor.message = Component.fromString(itip1 % self.dtsubs)
         processor.originator = RemoteCalendarUser("mailto:cuser01 at example.org")
         processor.recipient = LocalCalendarUser("urn:x-uid:user01", None)
         processor.method = "CANCEL"
@@ -5622,7 +5560,7 @@
         yield self.commit()
 
         # Get user01 data
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
@@ -5720,7 +5658,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -5732,7 +5670,7 @@
         cobj = yield self.calendarObjectUnderTest(name="data.ics", calendar_name="calendar", home="user01")
         processor.recipient_calendar_resource = cobj
         processor.recipient_calendar = (yield cobj.componentForUser("user01"))
-        processor.message = Component.fromString(itip1 % self.subs)
+        processor.message = Component.fromString(itip1 % self.dtsubs)
         processor.originator = RemoteCalendarUser("mailto:cuser01 at example.org")
         processor.recipient = LocalCalendarUser("urn:x-uid:user01", None)
         processor.method = "REQUEST"
@@ -5743,7 +5681,7 @@
         yield self.commit()
 
         # Get user01 data
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
@@ -5893,7 +5831,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -5905,7 +5843,7 @@
         cobj = yield self.calendarObjectUnderTest(name="data.ics", calendar_name="calendar", home="user01")
         processor.recipient_calendar_resource = cobj
         processor.recipient_calendar = (yield cobj.componentForUser("user01"))
-        processor.message = Component.fromString(itip1 % self.subs)
+        processor.message = Component.fromString(itip1 % self.dtsubs)
         processor.originator = RemoteCalendarUser("mailto:cuser01 at example.org")
         processor.recipient = LocalCalendarUser("urn:x-uid:user01", None)
         processor.method = "REQUEST"
@@ -5917,7 +5855,7 @@
 
         # Get user01 data
         ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails("user01")
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = pastUID
         relsubs["relID"] = relID
 
@@ -6096,7 +6034,7 @@
 END:VCALENDAR
 """
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -6117,7 +6055,7 @@
         cobj = yield self.calendarObjectUnderTest(name="data.ics", calendar_name="calendar", home="user01")
         processor.recipient_calendar_resource = cobj
         processor.recipient_calendar = (yield cobj.componentForUser("user01"))
-        processor.message = Component.fromString(itip1 % self.subs)
+        processor.message = Component.fromString(itip1 % self.dtsubs)
         processor.originator = RemoteCalendarUser("mailto:cuser01 at example.org")
         processor.recipient = LocalCalendarUser("urn:x-uid:user01", None)
         processor.method = "REQUEST"
@@ -6136,7 +6074,7 @@
 
         processor.recipient_calendar_resource = None
         processor.recipient_calendar = None
-        processor.message = Component.fromString(itip2 % self.subs)
+        processor.message = Component.fromString(itip2 % self.dtsubs)
         processor.originator = RemoteCalendarUser("mailto:cuser01 at example.org")
         processor.recipient = LocalCalendarUser("urn:x-uid:user01", None)
         processor.method = "REQUEST"
@@ -6497,7 +6435,7 @@
                     responses.add(recipient, responsecode.NOT_FOUND, reqstatus=iTIPRequestStatus.INVALID_CALENDAR_USER)
             return succeed(responses)
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertTrue(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -6538,7 +6476,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = newUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s\n%s" % (title, diff_iCalStrs(ical_future, data_future % relsubs),))
@@ -6894,7 +6832,7 @@
         # Create one event without active split
         self.patch(config.Scheduling.Options.Splitting, "Enabled", False)
         calendar = yield self.calendarUnderTest(name="calendar", home="user01")
-        component = Component.fromString(data_init % self.subs)
+        component = Component.fromString(data_init % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -6929,7 +6867,7 @@
             return oldScheduling(self, do_smart_merge, split_details)
         self.patch(ImplicitScheduler, "doImplicitScheduling", newScheduling)
 
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         yield self.failUnlessFailure(cobj.setComponent(component), AlreadyFinishedError)
         self.assertTrue(self.transactionUnderTest().timedout)
 
@@ -6973,7 +6911,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = newUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -7235,7 +7173,7 @@
         # Create one event without active split
         self.patch(config.Scheduling.Options.Splitting, "Enabled", False)
         calendar = yield self.calendarUnderTest(name="calendar", home="user01")
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -7278,7 +7216,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = newUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -7578,7 +7516,7 @@
 """
 
         # Create it
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -7706,7 +7644,7 @@
 """
 
         # Create it
-        component = Component.fromString(data % self.subs)
+        component = Component.fromString(data % self.dtsubs)
         cobj = yield calendar.createCalendarObjectWithName("data1.ics", component)
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -7732,7 +7670,7 @@
 
         # Update it
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
-        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs))
+        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.dtsubs))
         oldname = oldobj.name()
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -7769,7 +7707,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = newUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -7808,7 +7746,7 @@
 
         # Update it
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
-        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back15_12h)s" % self.subs))
+        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back15_12h)s" % self.dtsubs))
         oldname = oldobj.name()
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -7845,7 +7783,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = newUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -7884,7 +7822,7 @@
 
         # Update it
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
-        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs))
+        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.dtsubs))
         oldname = oldobj.name()
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -7921,7 +7859,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = newUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -7940,7 +7878,7 @@
         cal = yield self.calendarUnderTest(name="calendar", home="user02")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
-        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(now_back14)s" % self.subs)), InvalidSplit)
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(now_back14)s" % self.dtsubs)), InvalidSplit)
 
 
     @inlineCallbacks
@@ -7955,7 +7893,7 @@
         cal = yield self.calendarUnderTest(name="calendar", home="user02")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
-        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(now_back30)s" % self.subs)), InvalidSplit)
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(now_back30)s" % self.dtsubs)), InvalidSplit)
 
 
     @inlineCallbacks
@@ -7970,7 +7908,7 @@
         cal = yield self.calendarUnderTest(name="calendar", home="user02")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
-        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(now_fwd25)s" % self.subs)), InvalidSplit)
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(now_fwd25)s" % self.dtsubs)), InvalidSplit)
 
 
     @inlineCallbacks
@@ -7984,7 +7922,7 @@
 
         # Update it
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
-        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs), pastUID=pastUID)
+        oldobj = yield cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.dtsubs), pastUID=pastUID)
         oldname = oldobj.name()
         self.assertFalse(hasattr(cobj, "_workItems"))
         yield self.commit()
@@ -8023,7 +7961,7 @@
 
         # Verify user01 data
         title = "user01"
-        relsubs = dict(self.subs)
+        relsubs = dict(self.dtsubs)
         relsubs["uid"] = newUID
         relsubs["relID"] = relID
         self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, "Failed future: %s" % (title,))
@@ -8063,7 +8001,7 @@
 
         # Update it
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
-        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs), pastUID="12345-67890"), InvalidSplit)
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.dtsubs), pastUID="12345-67890"), InvalidSplit)
 
 
     @inlineCallbacks
@@ -8093,13 +8031,13 @@
         yield self._setupSplitAt()
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user01")
-        component = Component.fromString(data_existing % self.subs)
+        component = Component.fromString(data_existing % self.dtsubs)
         yield calendar.createCalendarObjectWithName("data2.ics", component)
         yield self.commit()
 
         # Update it
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
-        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.subs), pastUID="12345-67890-existing"), InvalidSplit)
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now_back14)s" % self.dtsubs), pastUID="12345-67890-existing"), InvalidSplit)
 
 
     @inlineCallbacks
@@ -8114,10 +8052,10 @@
         cal = yield self.calendarUnderTest(name="calendar", home="user02")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
-        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(nowDate)s" % self.subs)), InvalidSplit)
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(nowDate)s" % self.dtsubs)), InvalidSplit)
 
         # DTSTART DATE-TIME UTC/rid DATE-TIME floating
-        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(nowFloating)s" % self.subs)), InvalidSplit)
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText("%(nowFloating)s" % self.dtsubs)), InvalidSplit)
 
         data_floating = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -8137,20 +8075,20 @@
 """
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user01")
-        component = Component.fromString(data_floating % self.subs)
+        component = Component.fromString(data_floating % self.dtsubs)
         yield calendar.createCalendarObjectWithName("data2.ics", component)
         yield self.commit()
 
         # DTSTART DATE/rid DATE-TIME floating
         cobj = yield self.calendarObjectUnderTest(name="data2.ics", calendar_name="calendar", home="user01")
-        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(nowFloating)s" % self.subs)), InvalidSplit)
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(nowFloating)s" % self.dtsubs)), InvalidSplit)
 
         # DTSTART DATE/rid DATE-TIME UTC
-        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now)s" % self.subs)), InvalidSplit)
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText("%(now)s" % self.dtsubs)), InvalidSplit)
 
 
 
-class TimeRangeUpdateOptimization(CommonCommonTests, unittest.TestCase):
+class TimeRangeUpdateOptimization(CommonCommonTests, DateTimeSubstitutionsMixin, unittest.TestCase):
     """
     CalendarObject time range optimization tests.
     """
@@ -8162,7 +8100,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8177,7 +8115,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event #2
 DTSTAMP:20100203T013909Z
@@ -8192,7 +8130,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T130000Z
+DTSTART:{nowDate}T130000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8207,7 +8145,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8223,7 +8161,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 STATUS:CANCELLED
@@ -8239,7 +8177,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8255,7 +8193,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8271,7 +8209,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8287,12 +8225,12 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
 RRULE:FREQ=DAILY
-EXDATE:{now}T120000Z
+EXDATE:{nowDate}T120000Z
 END:VEVENT
 END:VCALENDAR
 """
@@ -8304,12 +8242,12 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
 RRULE:FREQ=DAILY
-RDATE:{now}T150000Z
+RDATE:{nowDate}T150000Z
 END:VEVENT
 END:VCALENDAR
 """
@@ -8321,12 +8259,7 @@
         yield self.buildStoreAndDirectory()
         yield self.populate()
 
-        self.now = DateTime.getNowUTC()
-        self.now.setDateOnly(True)
-        self.now1 = self.now.duplicate()
-        self.now1.offsetDay(1)
-        self.now2 = self.now.duplicate()
-        self.now2.offsetDay(2)
+        self.setupDateTimeValues()
 
         self.trcount = 0
         base_addInstances = CalendarObject._addInstances
@@ -8370,7 +8303,7 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
@@ -8384,14 +8317,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT does not cause T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT2.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT2.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
@@ -8407,14 +8340,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT does cause T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT2.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT2.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8428,14 +8361,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT causes T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT3.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT3.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8449,14 +8382,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT causes T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT4.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT4.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8470,14 +8403,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT causes T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT5.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT5.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8491,14 +8424,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT causes T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT6.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT6.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8512,14 +8445,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT causes T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT8.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT8.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8533,14 +8466,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT causes T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT9.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT9.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8554,14 +8487,14 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest()
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.EVENT7.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 1)
 
         # Second PUT causes T-R change
         cobj = yield self.calendarObjectUnderTest()
-        yield cobj.setComponent(Component.fromString(self.EVENT10.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.EVENT10.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 2)
@@ -8574,7 +8507,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8592,7 +8525,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8610,7 +8543,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event #2
 DTSTAMP:20100203T013909Z
@@ -8628,7 +8561,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T140000Z
+DTSTART:{nowDate}T140000Z
 DURATION:PT1H
 SUMMARY:New Event #2
 DTSTAMP:20100203T013909Z
@@ -8650,7 +8583,7 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 3)
@@ -8659,21 +8592,21 @@
         cal = yield self.calendarUnderTest(home="user02", name="calendar")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
-        yield cobjs[0].setComponent(Component.fromString(self.INVITE2.format(now=self.now.getText())))
+        yield cobjs[0].setComponent(Component.fromString(self.INVITE2.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 5)
 
         # Organizer summary change does not cause T-R change (except for inbox item)
         cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
-        yield cobj.setComponent(Component.fromString(self.INVITE3.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.INVITE3.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 6)
 
         # Organizer dtstart change causes T-R change
         cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
-        yield cobj.setComponent(Component.fromString(self.INVITE4.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.INVITE4.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 9)
@@ -8692,7 +8625,7 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE1.format(now=self.now.getText())))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE1.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 3)
@@ -8701,21 +8634,21 @@
         cal = yield self.calendarUnderTest(home="user02", name="calendar")
         cobjs = yield cal.calendarObjects()
         self.assertEqual(len(cobjs), 1)
-        yield cobjs[0].setComponent(Component.fromString(self.INVITE2.format(now=self.now.getText())))
+        yield cobjs[0].setComponent(Component.fromString(self.INVITE2.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 5)
 
         # Organizer summary change causes T-R change
         cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
-        yield cobj.setComponent(Component.fromString(self.INVITE3.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.INVITE3.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 8)
 
         # Organizer dtstart change causes T-R change
         cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
-        yield cobj.setComponent(Component.fromString(self.INVITE4.format(now=self.now.getText())))
+        yield cobj.setComponent(Component.fromString(self.INVITE4.format(**self.dtsubs)))
         yield self.commit()
 
         self.assertEqual(self.trcount, 11)
@@ -8728,7 +8661,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8739,8 +8672,8 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-RECURRENCE-ID:{now1}T120000Z
-DTSTART:{now1}T120000Z
+RECURRENCE-ID:{nowDate_fwd1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event now1
 DTSTAMP:20100203T013909Z
@@ -8758,8 +8691,8 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-RECURRENCE-ID:{now1}T120000Z
-DTSTART:{now1}T120000Z
+RECURRENCE-ID:{nowDate_fwd1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event now1
 DTSTAMP:20100203T013909Z
@@ -8777,7 +8710,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8788,8 +8721,8 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-RECURRENCE-ID:{now1}T120000Z
-DTSTART:{now1}T120000Z
+RECURRENCE-ID:{nowDate_fwd1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event now1
 DTSTAMP:20100203T013909Z
@@ -8800,8 +8733,8 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-RECURRENCE-ID:{now2}T120000Z
-DTSTART:{now2}T120000Z
+RECURRENCE-ID:{nowDate_fwd2}T120000Z
+DTSTART:{nowDate_fwd2}T120000Z
 DURATION:PT1H
 SUMMARY:New Event now2
 DTSTAMP:20100203T013909Z
@@ -8819,7 +8752,7 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-DTSTART:{now}T120000Z
+DTSTART:{nowDate}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8830,8 +8763,8 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-RECURRENCE-ID:{now1}T120000Z
-DTSTART:{now1}T120000Z
+RECURRENCE-ID:{nowDate_fwd1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event now1
 DTSTAMP:20100203T013909Z
@@ -8841,8 +8774,8 @@
 BEGIN:VEVENT
 CREATED:20100203T013849Z
 UID:uid1
-RECURRENCE-ID:{now2}T120000Z
-DTSTART:{now2}T120000Z
+RECURRENCE-ID:{nowDate_fwd2}T120000Z
+DTSTART:{nowDate_fwd2}T120000Z
 DURATION:PT1H
 SUMMARY:New Event now2
 DTSTAMP:20100203T013909Z
@@ -8866,11 +8799,7 @@
 
         # First PUT causes T-R change
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
-        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE_OVERRIDE1.format(
-            now=self.now.getText(),
-            now1=self.now1.getText(),
-            now2=self.now2.getText(),
-        )))
+        yield cal.createObjectResourceWithName("1.ics", Component.fromString(self.INVITE_OVERRIDE1.format(**self.dtsubs)))
         yield self.commit()
 
         # Wait for it to complete
@@ -8880,11 +8809,7 @@
 
         # Organizer adds attendee to override causes T-R change (except for their item)
         cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
-        yield cobj.setComponent(Component.fromString(self.INVITE_OVERRIDE3.format(
-            now=self.now.getText(),
-            now1=self.now1.getText(),
-            now2=self.now2.getText(),
-        )))
+        yield cobj.setComponent(Component.fromString(self.INVITE_OVERRIDE3.format(**self.dtsubs)))
         yield self.commit()
 
         # Wait for it to complete
@@ -8894,11 +8819,7 @@
 
         # Organizer removes attendee from override causes T-R change (except for their item)
         cobj = yield self.calendarObjectUnderTest(home="user01", calendar_name="calendar")
-        yield cobj.setComponent(Component.fromString(self.INVITE_OVERRIDE4.format(
-            now=self.now.getText(),
-            now1=self.now1.getText(),
-            now2=self.now2.getText(),
-        )))
+        yield cobj.setComponent(Component.fromString(self.INVITE_OVERRIDE4.format(**self.dtsubs)))
         yield self.commit()
 
         # Wait for it to complete
@@ -8908,7 +8829,7 @@
 
 
 
-class GroupExpand(CommonCommonTests, unittest.TestCase):
+class GroupExpand(CommonCommonTests, DateTimeSubstitutionsMixin, unittest.TestCase):
     """
     CalendarObject group attendee expansion.
     """
@@ -8926,26 +8847,11 @@
 
         yield self.populate()
 
-        now = DateTime.getNowUTC()
-        now.setDateOnly(True)
-        past1 = now.duplicate()
-        past1.offsetDay(-1)
-        past2 = now.duplicate()
-        past2.offsetDay(-2)
-        past400 = now.duplicate()
+        self.setupDateTimeValues()
+
+        past400 = self.nowDate.duplicate()
         past400.offsetDay(-400)
-        now1 = now.duplicate()
-        now1.offsetDay(1)
-        now2 = now.duplicate()
-        now2.offsetDay(2)
-        self.subs = {
-            "now": now,
-            "past1": past1,
-            "past2": past2,
-            "past400": past400,
-            "now1": now1,
-            "now2": now2,
-        }
+        self.dtsubs["nowDate_back400"] = past400
 
 
     @inlineCallbacks
@@ -8984,7 +8890,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -8993,7 +8899,7 @@
 ATTENDEE:urn:x-uid:group01
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9002,7 +8908,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9011,7 +8917,7 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9038,7 +8944,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9046,7 +8952,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:mailto:user01 at example.com
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event2 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9054,7 +8960,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9063,7 +8969,7 @@
 ATTENDEE:urn:x-uid:group01
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9072,7 +8978,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9082,8 +8988,17 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
+        # Group user has no data
+        cal = yield self.calendarUnderTest(home="user02", name="calendar")
+        cobjs = yield cal.calendarObjects()
+        self.assertEqual(len(cobjs), 0)
+        cal = yield self.calendarUnderTest(home="user02", name="inbox")
+        cobjs = yield cal.calendarObjects()
+        self.assertEqual(len(cobjs), 0)
+        yield self.commit()
+
         # PUT does not cause expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
         yield cal.createObjectResourceWithName("1.ics", Component.fromString(event1))
@@ -9106,7 +9021,18 @@
         links = yield calobj.groupEventLinks()
         self.assertEqual(len(links), 1)
 
+        # Group user has invite data
+        cal = yield self.calendarUnderTest(home="user02", name="calendar")
+        cobjs = yield cal.calendarObjects()
+        self.assertEqual(len(cobjs), 1)
+        cal = yield self.calendarUnderTest(home="user02", name="inbox")
+        cobjs = yield cal.calendarObjects()
+        self.assertEqual(len(cobjs), 1)
+        comp = yield cobjs[0].componentForUser()
+        self.assertTrue("METHOD:REQUEST" in str(comp))
+        yield self.commit()
 
+
     @inlineCallbacks
     def test_expand_update_existing(self):
         """
@@ -9119,7 +9045,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9128,7 +9054,7 @@
 ATTENDEE:urn:x-uid:group01
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event2 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9137,7 +9063,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9147,7 +9073,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event3 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9156,7 +9082,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T130000Z
+DTSTART:{nowDate_fwd1}T130000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9166,7 +9092,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9175,7 +9101,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T130000Z
+DTSTART:{nowDate_fwd1}T130000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9185,7 +9111,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9231,7 +9157,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9241,7 +9167,7 @@
 RRULE:FREQ=DAILY
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9250,7 +9176,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9260,7 +9186,7 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9287,7 +9213,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9296,7 +9222,7 @@
 RRULE:FREQ=DAILY
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event2 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9304,7 +9230,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9314,7 +9240,7 @@
 RRULE:FREQ=DAILY
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9323,7 +9249,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9334,7 +9260,7 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT does not cause expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9371,7 +9297,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9381,7 +9307,7 @@
 RRULE:FREQ=DAILY
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event2 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9390,7 +9316,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T120000Z
+DTSTART:{nowDate_fwd1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9401,7 +9327,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event3 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9410,7 +9336,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T130000Z
+DTSTART:{nowDate_fwd1}T130000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9421,7 +9347,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9430,7 +9356,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{now1}T130000Z
+DTSTART:{nowDate_fwd1}T130000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9441,7 +9367,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9487,7 +9413,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9496,7 +9422,7 @@
 ATTENDEE:urn:x-uid:group01
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9505,7 +9431,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9514,7 +9440,7 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9541,7 +9467,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9549,7 +9475,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:mailto:user01 at example.com
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event2 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9557,7 +9483,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9566,7 +9492,7 @@
 ATTENDEE:urn:x-uid:group01
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9575,7 +9501,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9585,7 +9511,7 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT does not cause expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9622,7 +9548,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9631,7 +9557,7 @@
 ATTENDEE:urn:x-uid:group01
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event2 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9640,7 +9566,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9650,7 +9576,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         event3 = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9659,7 +9585,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{past1}T130000Z
+DTSTART:{nowDate_back1}T130000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9669,7 +9595,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9678,7 +9604,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{past1}T130000Z
+DTSTART:{nowDate_back1}T130000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9688,7 +9614,7 @@
 SUMMARY:New Event #2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9735,7 +9661,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9745,7 +9671,7 @@
 RRULE:FREQ=YEARLY;INTERVAL=2
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9754,7 +9680,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{past1}T120000Z
+DTSTART:{nowDate_back1}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9764,7 +9690,7 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -9792,7 +9718,7 @@
 CALSCALE:GREGORIAN
 BEGIN:VEVENT
 UID:uid1
-DTSTART:{past400}T120000Z
+DTSTART:{nowDate_back400}T120000Z
 DURATION:PT1H
 SUMMARY:New Event
 DTSTAMP:20100203T013909Z
@@ -9802,7 +9728,7 @@
 RRULE:FREQ=YEARLY;INTERVAL=4
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         result = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -9811,7 +9737,7 @@
 BEGIN:VEVENT
 UID:uid1
 DTSTAMP:20100203T013909Z
-DTSTART:{past400}T120000Z
+DTSTART:{nowDate_back400}T120000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;PARTSTAT=ACCEPTED:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -9821,7 +9747,7 @@
 SUMMARY:New Event
 END:VEVENT
 END:VCALENDAR
-""".format(**self.subs)
+""".format(**self.dtsubs)
 
         # PUT causes expansion
         cal = yield self.calendarUnderTest(home="user01", name="calendar")

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/util.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/util.py	2015-06-30 18:57:02 UTC (rev 14932)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/util.py	2015-06-30 19:35:01 UTC (rev 14933)
@@ -15,8 +15,10 @@
 # limitations under the License.
 ##
 from twisted.trial.unittest import TestCase
+from twisted.internet.defer import inlineCallbacks
 from twext.python.clsprop import classproperty
-from twisted.internet.defer import inlineCallbacks
+from twistedcaldav.ical import Component, normalize_iCalStr, diff_iCalStrs
+from pycalendar.datetime import DateTime
 
 """
 Store test utility functions
@@ -70,3 +72,96 @@
                 },
             },
         }
+
+
+
+class DateTimeSubstitutionsMixin(object):
+    """
+    Mix-in class for tests that defines a set of str.format() substitutions for date-time values
+    relative to the current time. This allows tests to always use relative-to-now values rather
+    than fixed values which may become in valid in the future (e.g., a test that needs an event
+    in the future and uses 2017 works fine up until 2017 and then starts to fail.
+    """
+
+    def setupDateTimeValues(self):
+
+        self.dtsubs = {}
+
+        # Set of "now" values that are directly accessible
+        self.now = DateTime.getNowUTC()
+        self.now.setHHMMSS(0, 0, 0)
+        self.now12 = DateTime.getNowUTC()
+        self.now12.setHHMMSS(12, 0, 0)
+        self.nowDate = self.now.duplicate()
+        self.nowDate.setDateOnly(True)
+        self.nowFloating = self.now.duplicate()
+        self.nowFloating.setTimezoneID(None)
+
+        self.dtsubs["now"] = self.now
+        self.dtsubs["now12"] = self.now12
+        self.dtsubs["nowDate"] = self.nowDate
+        self.dtsubs["nowFloating"] = self.nowFloating
+
+        # Values going 30 days back from now
+        for i in range(30):
+            attrname = "now_back%s" % (i + 1,)
+            setattr(self, attrname, self.now.duplicate())
+            getattr(self, attrname).offsetDay(-(i + 1))
+            self.dtsubs[attrname] = getattr(self, attrname)
+
+            attrname_12h = "now_back%s_12h" % (i + 1,)
+            setattr(self, attrname_12h, getattr(self, attrname).duplicate())
+            getattr(self, attrname_12h).offsetHours(12)
+            self.dtsubs[attrname_12h] = getattr(self, attrname_12h)
+
+            attrname_1 = "now_back%s_1" % (i + 1,)
+            setattr(self, attrname_1, getattr(self, attrname).duplicate())
+            getattr(self, attrname_1).offsetSeconds(-1)
+            self.dtsubs[attrname_1] = getattr(self, attrname_1)
+
+            attrname = "nowDate_back%s" % (i + 1,)
+            setattr(self, attrname, self.nowDate.duplicate())
+            getattr(self, attrname).offsetDay(-(i + 1))
+            self.dtsubs[attrname] = getattr(self, attrname)
+
+            attrname = "nowFloating_back%s" % (i + 1,)
+            setattr(self, attrname, self.nowFloating.duplicate())
+            getattr(self, attrname).offsetDay(-(i + 1))
+            self.dtsubs[attrname] = getattr(self, attrname)
+
+            attrname_1 = "nowFloating_back%s_1" % (i + 1,)
+            setattr(self, attrname_1, getattr(self, attrname).duplicate())
+            getattr(self, attrname_1).offsetSeconds(-1)
+            self.dtsubs[attrname_1] = getattr(self, attrname_1)
+
+        # Values going 30 days forward from now
+        for i in range(30):
+            attrname = "now_fwd%s" % (i + 1,)
+            setattr(self, attrname, self.now.duplicate())
+            getattr(self, attrname).offsetDay(i + 1)
+            self.dtsubs[attrname] = getattr(self, attrname)
+
+            attrname_12h = "now_fwd%s_12h" % (i + 1,)
+            setattr(self, attrname_12h, getattr(self, attrname).duplicate())
+            getattr(self, attrname_12h).offsetHours(12)
+            self.dtsubs[attrname_12h] = getattr(self, attrname_12h)
+
+            attrname = "nowDate_fwd%s" % (i + 1,)
+            setattr(self, attrname, self.nowDate.duplicate())
+            getattr(self, attrname).offsetDay(i + 1)
+            self.dtsubs[attrname] = getattr(self, attrname)
+
+            attrname = "nowFloating_fwd%s" % (i + 1,)
+            setattr(self, attrname, self.nowFloating.duplicate())
+            getattr(self, attrname).offsetDay(i + 1)
+            self.dtsubs[attrname] = getattr(self, attrname)
+
+
+    def assertEqualCalendarData(self, cal1, cal2):
+        if isinstance(cal1, str):
+            cal1 = Component.fromString(cal1)
+        if isinstance(cal2, str):
+            cal2 = Component.fromString(cal2)
+        ncal1 = normalize_iCalStr(cal1)
+        ncal2 = normalize_iCalStr(cal2)
+        self.assertEqual(ncal1, ncal2, msg=diff_iCalStrs(ncal1, ncal2))

Modified: CalendarServer/trunk/txdav/common/datastore/test/util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/util.py	2015-06-30 18:57:02 UTC (rev 14932)
+++ CalendarServer/trunk/txdav/common/datastore/test/util.py	2015-06-30 19:35:01 UTC (rev 14933)
@@ -49,7 +49,7 @@
 
 from twistedcaldav import ical
 from twistedcaldav.config import config, ConfigDict
-from twistedcaldav.ical import Component as VComponent, Component
+from twistedcaldav.ical import Component as VComponent
 from twistedcaldav.stdconfig import DEFAULT_CONFIG
 from twistedcaldav.vcard import Component as ABComponent
 
@@ -553,36 +553,7 @@
     return data % {"now": nowYear}
 
 
-relativeDateSubstitutions = {}
 
-
-def componentUpdate(data):
-    """
-    Update the supplied iCalendar data so that all dates are updated to the
-    current year.
-    """
-
-    if len(relativeDateSubstitutions) == 0:
-        now = DateTime.getToday()
-
-        relativeDateSubstitutions["now"] = now
-
-        for i in range(30):
-            attrname = "now_back%s" % (i + 1,)
-            dt = now.duplicate()
-            dt.offsetDay(-(i + 1))
-            relativeDateSubstitutions[attrname] = dt
-
-        for i in range(30):
-            attrname = "now_fwd%s" % (i + 1,)
-            dt = now.duplicate()
-            dt.offsetDay(i + 1)
-            relativeDateSubstitutions[attrname] = dt
-
-    return Component.fromString(data.format(**relativeDateSubstitutions))
-
-
-
 @inlineCallbacks
 def resetCalendarMD5s(md5s, store):
     """

Modified: CalendarServer/trunk/txdav/who/test/test_group_attendees.py
===================================================================
--- CalendarServer/trunk/txdav/who/test/test_group_attendees.py	2015-06-30 18:57:02 UTC (rev 14932)
+++ CalendarServer/trunk/txdav/who/test/test_group_attendees.py	2015-06-30 19:35:01 UTC (rev 14933)
@@ -27,13 +27,14 @@
 from twistedcaldav.config import config
 from twistedcaldav.ical import Component, normalize_iCalStr
 from txdav.caldav.datastore.sql_directory import GroupAttendeeRecord
-from txdav.caldav.datastore.test.util import populateCalendarsFrom, CommonCommonTests
+from txdav.caldav.datastore.test.util import populateCalendarsFrom, CommonCommonTests, \
+    DateTimeSubstitutionsMixin
 from txdav.who.directory import CalendarDirectoryRecordMixin
 from txdav.who.groups import GroupCacher
 import os
 
 
-class GroupAttendeeTestBase(CommonCommonTests, unittest.TestCase):
+class GroupAttendeeTestBase(CommonCommonTests, DateTimeSubstitutionsMixin, unittest.TestCase):
     """
     GroupAttendeeReconciliation tests
     """
@@ -50,6 +51,8 @@
         )
         yield self.populate()
 
+        self.setupDateTimeValues()
+
         self.paths = {}
 
 
@@ -98,7 +101,7 @@
 
             return event
 
-        self.assertEqual(
+        self.assertEqualCalendarData(
             orderMemberValues(Component.fromString(normalize_iCalStr(iCalStr1))),
             orderMemberValues(Component.fromString(normalize_iCalStr(iCalStr2)))
         )
@@ -121,7 +124,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -137,7 +140,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
@@ -154,13 +157,13 @@
         yield self._verifyObjectResourceCount("user06", 0)
         yield self._verifyObjectResourceCount("user07", 0)
 
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_1)
+        self._assertICalStrEqual(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user06", 1)
         yield self._verifyObjectResourceCount("user07", 1)
@@ -180,7 +183,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -196,7 +199,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CUTYPE=X-SERVER-GROUP;SCHEDULE-STATUS=3.7:urn:uuid:FFFFFFFF-EEEE-DDDD-CCCC-BBBBBBBBBBBB
@@ -207,13 +210,13 @@
 END:VCALENDAR
 """
 
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1))
+        self.assertEqualCalendarData(vcalendar, data_get_1.format(**self.dtsubs))
 
 
     @inlineCallbacks
@@ -230,7 +233,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -247,7 +250,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user02
@@ -258,13 +261,13 @@
 END:VEVENT
 END:VCALENDAR
 """
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1))
+        self.assertEqualCalendarData(vcalendar, data_get_1.format(**self.dtsubs))
 
 
     @inlineCallbacks
@@ -287,7 +290,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -303,7 +306,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 04;CUTYPE=X-SERVER-GROUP;SCHEDULE-STATUS=2.7:urn:x-uid:group04
@@ -319,13 +322,13 @@
 END:VCALENDAR
 """
 
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_1)
+        self._assertICalStrEqual(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user06", 1)
         yield self._verifyObjectResourceCount("user07", 1)
@@ -353,7 +356,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -371,7 +374,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -387,13 +390,13 @@
 END:VEVENT
 END:VCALENDAR"""
 
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_1)
+        self._assertICalStrEqual(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user06", 1)
         yield self._verifyObjectResourceCount("user07", 1)
@@ -414,7 +417,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -430,7 +433,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -444,7 +447,7 @@
         groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
@@ -459,7 +462,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1))
+        self.assertEqualCalendarData(vcalendar, data_get_1.format(**self.dtsubs))
 
 
 
@@ -478,7 +481,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -494,7 +497,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -511,7 +514,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -530,7 +533,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -558,13 +561,13 @@
         self.assertEqual(len(wps), 0)
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2))
+        self.assertEqualCalendarData(vcalendar, data_get_2.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 0)
         yield self.commit()
@@ -582,7 +585,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_3))
+        self.assertEqualCalendarData(vcalendar, data_get_3.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 1)
         yield self.commit()
@@ -595,7 +598,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_4))
+        self.assertEqualCalendarData(vcalendar, data_get_4.format(**self.dtsubs))
 
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
         cobjs = yield cal.objectResources()
@@ -617,7 +620,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 SUMMARY:event {0}
 UID:event{0}@ninevah.local
@@ -633,7 +636,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event{0}@ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -650,7 +653,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event{0}@ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -669,7 +672,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event{0}@ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 0{0};EMAIL=user0{0}@example.com;RSVP=TRUE:urn:x-uid:user0{0}
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -700,13 +703,13 @@
 
         for i in userRange:
             calendar = yield self.calendarUnderTest(name="calendar", home="user0{0}".format(i))
-            vcalendar = Component.fromString(data_put_1.format(i))
+            vcalendar = Component.fromString(data_put_1.format(i, **self.dtsubs))
             yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
             yield self.commit()
 
             cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user0{0}".format(i))
             vcalendar = yield cobj.component()
-            self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2.format(i)))
+            self.assertEqualCalendarData(vcalendar, data_get_2.format(i, **self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 0)
         yield self.commit()
@@ -725,7 +728,7 @@
         for i in userRange:
             cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user0{0}".format(i))
             vcalendar = yield cobj.component()
-            self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_3.format(i)))
+            self.assertEqualCalendarData(vcalendar, data_get_3.format(i, **self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", len(userRange))
         yield self.commit()
@@ -739,7 +742,7 @@
         for i in userRange:
             cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user0{0}".format(i))
             vcalendar = yield cobj.component()
-            self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_4.format(i)))
+            self.assertEqualCalendarData(vcalendar, data_get_4.format(i, **self.dtsubs))
 
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
         cobjs = yield cal.objectResources()
@@ -762,7 +765,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -779,7 +782,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -795,7 +798,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -813,7 +816,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -834,7 +837,7 @@
         groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
@@ -848,11 +851,11 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1))
+        self.assertEqualCalendarData(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 1)
 
-        vcalendar = Component.fromString(data_put_2)
+        vcalendar = Component.fromString(data_put_2.format(**self.dtsubs))
         yield cobj.setComponent(vcalendar)
         yield self.commit()
 
@@ -860,7 +863,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2))
+        self.assertEqualCalendarData(vcalendar, data_get_2.format(**self.dtsubs))
 
         wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "group01")
         self.assertEqual(len(wps), 0)
@@ -884,7 +887,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2))
+        self.assertEqualCalendarData(vcalendar, data_get_2.format(**self.dtsubs))
 
         '''
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
@@ -916,9 +919,9 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
-RRULE:FREQ=DAILY;UNTIL=20240101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SUMMARY:event 1
 UID:event1 at ninevah.local
 ORGANIZER:MAILTO:user02 at example.com
@@ -934,9 +937,9 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
-RRULE:FREQ=DAILY;UNTIL=20140101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_back1}T100000
 SUMMARY:event 1
 UID:event1 at ninevah.local
 ORGANIZER:MAILTO:user02 at example.com
@@ -951,14 +954,14 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-RRULE:FREQ=DAILY;UNTIL=20240101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SUMMARY:event 1
 END:VEVENT
 END:VCALENDAR
@@ -970,13 +973,13 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-RRULE:FREQ=DAILY;UNTIL=20140101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_back1}T100000
 SEQUENCE:1
 SUMMARY:event 1
 END:VEVENT
@@ -992,7 +995,7 @@
         groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
@@ -1006,11 +1009,11 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1))
+        self.assertEqualCalendarData(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 1)
 
-        vcalendar = Component.fromString(data_put_2)
+        vcalendar = Component.fromString(data_put_2.format(**self.dtsubs))
         yield cobj.setComponent(vcalendar)
         yield self.commit()
 
@@ -1018,7 +1021,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2))
+        self.assertEqualCalendarData(vcalendar, data_get_2.format(**self.dtsubs))
 
         wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "group01")
         if len(wps): # This is needed because the test currently fails and does actually create job items we have to wait for
@@ -1043,7 +1046,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2))
+        self.assertEqualCalendarData(vcalendar, data_get_2.format(**self.dtsubs))
 
 
     @inlineCallbacks
@@ -1059,9 +1062,9 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
-RRULE:FREQ=DAILY;UNTIL=20240101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SUMMARY:event 1
 UID:event1 at ninevah.local
 ORGANIZER:MAILTO:user02 at example.com
@@ -1076,14 +1079,14 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-RRULE:FREQ=DAILY;UNTIL=20240101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SUMMARY:event 1
 END:VEVENT
 END:VCALENDAR
@@ -1095,14 +1098,14 @@
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com:urn:x-uid:group01
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-RRULE:FREQ=DAILY;UNTIL=20240101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SUMMARY:event 1
 TRANSP:TRANSPARENT
 END:VEVENT
@@ -1120,7 +1123,7 @@
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-{relatedTo}RRULE:FREQ=DAILY;UNTIL=20240101T100000
+{relatedTo}RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SEQUENCE:2
 SUMMARY:event 1
 END:VEVENT
@@ -1131,7 +1134,7 @@
 CALSCALE:GREGORIAN
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
-{uid}DTSTART:20120101T100000Z
+{uid}DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -1156,7 +1159,7 @@
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-{relatedTo}RRULE:FREQ=DAILY;UNTIL=20240101T100000
+{relatedTo}RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SEQUENCE:2
 STATUS:CANCELLED
 SUMMARY:event 1
@@ -1169,7 +1172,7 @@
 CALSCALE:GREGORIAN
 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
 BEGIN:VEVENT
-{uid}DTSTART:20120101T100000Z
+{uid}DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com:urn:x-uid:group01
@@ -1191,21 +1194,26 @@
         groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1))
+        self.assertEqualCalendarData(vcalendar, data_get_1.format(**self.dtsubs))
 
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
         cobjs = yield cal.objectResources()
         self.assertEqual(len(cobjs), 1)
         vcalendar = yield cobjs[0].componentForUser()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1_user01))
+        self.assertEqualCalendarData(vcalendar, data_get_1_user01.format(**self.dtsubs))
         user01_cname = cobjs[0].name()
 
+        cal = yield self.calendarUnderTest(name="inbox", home="user01")
+        cobjs = yield cal.objectResources()
+        self.assertEqual(len(cobjs), 1)
+        yield cobjs[0].remove()
+
         self.patch(CalendarDirectoryRecordMixin, "expandedMembers", expandedMembers)
 
         wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "group01")
@@ -1225,22 +1233,13 @@
                     "uid": component.getProperty("UID"),
                 }
                 break
+            props.update(self.dtsubs)
 
             if cobj.name() == "data1.ics":
-                self.assertEqual(
-                    normalize_iCalStr(vcalendar),
-                    normalize_iCalStr(
-                        data_get_2.format(**props)
-                    )
-                )
+                self.assertEqualCalendarData(vcalendar, data_get_2.format(**props))
                 props_orig = props
             else:
-                self.assertEqual(
-                    normalize_iCalStr(vcalendar),
-                    normalize_iCalStr(
-                        data_get_3.format(**props)
-                    )
-                )
+                self.assertEqualCalendarData(vcalendar, data_get_3.format(**props))
                 props_new = props
 
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
@@ -1248,21 +1247,17 @@
         for cobj in cobjs:
             vcalendar = yield cobj.componentForUser()
             if cobj.name() == user01_cname:
-                self.assertEqual(
-                    normalize_iCalStr(vcalendar),
-                    normalize_iCalStr(
-                        data_get_2_user01.format(**props_orig)
-                    )
-                )
+                self.assertEqualCalendarData(vcalendar, data_get_2_user01.format(**props_orig))
             else:
-                self.assertEqual(
-                    normalize_iCalStr(vcalendar),
-                    normalize_iCalStr(
-                        data_get_3_user01.format(**props_new)
-                    )
-                )
+                self.assertEqualCalendarData(vcalendar, data_get_3_user01.format(**props_new))
 
+        cal = yield self.calendarUnderTest(name="inbox", home="user01")
+        cobjs = yield cal.objectResources()
+        self.assertEqual(len(cobjs), 1)
+        comp = yield cobjs[0].componentForUser()
+        self.assertTrue("METHOD:CANCEL" in str(comp))
 
+
     @inlineCallbacks
     def test_groupChangeLargerSpanningEvent(self):
         """
@@ -1276,9 +1271,9 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
-RRULE:FREQ=DAILY;UNTIL=20240101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SUMMARY:event 1
 UID:event1 at ninevah.local
 ORGANIZER:MAILTO:user02 at example.com
@@ -1293,13 +1288,13 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20120101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-RRULE:FREQ=DAILY;UNTIL=20240101T100000
+RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SUMMARY:event 1
 END:VEVENT
 END:VCALENDAR
@@ -1317,7 +1312,7 @@
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-{relatedTo}RRULE:FREQ=DAILY;UNTIL=20240101T100000
+{relatedTo}RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SEQUENCE:2
 SUMMARY:event 1
 END:VEVENT
@@ -1329,7 +1324,7 @@
 CALSCALE:GREGORIAN
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
-{uid}DTSTART:20120101T100000Z
+{uid}DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -1353,7 +1348,7 @@
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;MEMBER="urn:x-uid:group01";PARTSTAT=NEEDS-ACTION;RSVP=TRUE:urn:x-uid:user01
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 02;EMAIL=user02 at example.com:urn:x-uid:user02
-{relatedTo}RRULE:FREQ=DAILY;UNTIL=20240101T100000
+{relatedTo}RRULE:FREQ=DAILY;UNTIL={nowDate_fwd20}T100000
 SEQUENCE:2
 SUMMARY:event 1
 TRANSP:TRANSPARENT
@@ -1373,13 +1368,13 @@
         groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_1))
+        self.assertEqualCalendarData(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 0)
 
@@ -1402,31 +1397,19 @@
                     "uid": component.getProperty("UID"),
                 }
                 break
+            props.update(self.dtsubs)
 
             if cobj.name() == "data1.ics":
-                self.assertEqual(
-                    normalize_iCalStr(vcalendar),
-                    normalize_iCalStr(
-                        data_get_2.format(**props)
-                    )
-                )
+                self.assertEqualCalendarData(vcalendar, data_get_2.format(**props))
                 props_orig = props
             else:
-                self.assertEqual(
-                    normalize_iCalStr(vcalendar),
-                    normalize_iCalStr(
-                        data_get_3.format(**props)
-                    )
-                )
+                self.assertEqualCalendarData(vcalendar, data_get_3.format(**props))
 
         cal = yield self.calendarUnderTest(name="calendar", home="user01")
         cobjs = yield cal.objectResources()
         self.assertEqual(len(cobjs), 1)
         vcalendar = yield cobjs[0].componentForUser()
-        self.assertEqual(
-            normalize_iCalStr(vcalendar),
-            normalize_iCalStr(data_get_2_user01.format(**props_orig))
-        )
+        self.assertEqualCalendarData(vcalendar, data_get_2_user01.format(**props_orig))
 
 
     @inlineCallbacks
@@ -1452,7 +1435,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -1470,7 +1453,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -1492,7 +1475,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -1515,16 +1498,16 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
 ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
 ATTENDEE;CN=Group 03;CUTYPE=X-SERVER-GROUP;EMAIL=group03 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group03
-ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 ATTENDEE;CN=User 07;EMAIL=user07 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user07
 ATTENDEE;CN=User 08;EMAIL=user08 at example.com;MEMBER="urn:x-uid:group02","urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user08
 ATTENDEE;CN=User 09;EMAIL=user09 at example.com;MEMBER="urn:x-uid:group03";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user09
+ATTENDEE;CN=User 06;EMAIL=user06 at example.com;MEMBER="urn:x-uid:group02";PARTSTAT=NEEDS-ACTION;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:user06
 CREATED:20060101T150000Z
 ORGANIZER;CN=User 01;EMAIL=user01 at example.com:urn:x-uid:user01
 SEQUENCE:2
@@ -1543,13 +1526,13 @@
                 result = yield unpatchedRecordWithUID(self, uid)
             returnValue(result)
 
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_1)
+        self._assertICalStrEqual(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user06", 1)
         yield self._verifyObjectResourceCount("user07", 1)
@@ -1567,7 +1550,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_1)
+        self._assertICalStrEqual(vcalendar, data_get_1.format(**self.dtsubs))
 
         # remove group members run cacher again
         self.patch(DirectoryService, "recordWithUID", recordWithUID)
@@ -1579,7 +1562,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_2)
+        self._assertICalStrEqual(vcalendar, data_get_2.format(**self.dtsubs))
 
         cal = yield self.calendarUnderTest(name="calendar", home="user06")
         cobjs = yield cal.objectResources()
@@ -1598,7 +1581,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_3)
+        self._assertICalStrEqual(vcalendar, data_get_3.format(**self.dtsubs))
 
         cal = yield self.calendarUnderTest(name="calendar", home="user06")
         cobjs = yield cal.objectResources()
@@ -1631,7 +1614,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -1648,7 +1631,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
@@ -1670,7 +1653,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -1686,7 +1669,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 01;EMAIL=user01 at example.com;RSVP=TRUE:urn:x-uid:user01
 ATTENDEE;CN=Group 02;CUTYPE=X-SERVER-GROUP;EMAIL=group02 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group02
@@ -1701,13 +1684,13 @@
 END:VCALENDAR
 """
 
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_1)
+        self._assertICalStrEqual(vcalendar, data_get_1.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user06", 1)
         yield self._verifyObjectResourceCount("user07", 1)
@@ -1728,15 +1711,15 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_1)
+        self._assertICalStrEqual(vcalendar, data_get_1.format(**self.dtsubs))
 
-        vcalendar = Component.fromString(data_put_2)
+        vcalendar = Component.fromString(data_put_2.format(**self.dtsubs))
         yield cobj.setComponent(vcalendar)
         yield self.commit()
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
         vcalendar = yield cobj.component()
-        self._assertICalStrEqual(vcalendar, data_get_2)
+        self._assertICalStrEqual(vcalendar, data_get_2.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user06", 1)
         yield self._verifyObjectResourceCount("user07", 1)
@@ -1774,7 +1757,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 SUMMARY:event 1
 UID:event1 at ninevah.local
@@ -1790,7 +1773,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20240101T100000Z
+DTSTART:{nowDate_fwd20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -1805,7 +1788,7 @@
         groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
 
         groupsToRefresh = yield groupCacher.groupsToRefresh(self.transactionUnderTest())
@@ -1822,7 +1805,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2))
+        self.assertEqualCalendarData(vcalendar, data_get_2.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 1)
         groupsToRefresh = yield groupCacher.groupsToRefresh(self.transactionUnderTest())
@@ -1876,7 +1859,7 @@
 BEGIN:VEVENT
 DTSTAMP:20051222T205953Z
 CREATED:20060101T150000Z
-DTSTART:20140101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 RRULE:FREQ=DAILY
 DURATION:PT1H
 SUMMARY:event 1
@@ -1893,7 +1876,7 @@
 PRODID:-//Example Inc.//Example Calendar//EN
 BEGIN:VEVENT
 UID:event1 at ninevah.local
-DTSTART:20140101T100000Z
+DTSTART:{nowDate_back20}T100000Z
 DURATION:PT1H
 ATTENDEE;CN=User 02;EMAIL=user02 at example.com;RSVP=TRUE:urn:x-uid:user02
 ATTENDEE;CN=Group 01;CUTYPE=X-SERVER-GROUP;EMAIL=group01 at example.com;SCHEDULE-STATUS=2.7:urn:x-uid:group01
@@ -1909,7 +1892,7 @@
         groupCacher = GroupCacher(self.transactionUnderTest().directoryService())
 
         calendar = yield self.calendarUnderTest(name="calendar", home="user02")
-        vcalendar = Component.fromString(data_put_1)
+        vcalendar = Component.fromString(data_put_1.format(**self.dtsubs))
         yield calendar.createCalendarObjectWithName("data1.ics", vcalendar)
 
         groupsToRefresh = yield groupCacher.groupsToRefresh(self.transactionUnderTest())
@@ -1926,7 +1909,7 @@
 
         cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user02")
         vcalendar = yield cobj.component()
-        self.assertEqual(normalize_iCalStr(vcalendar), normalize_iCalStr(data_get_2))
+        self.assertEqualCalendarData(vcalendar, data_get_2.format(**self.dtsubs))
 
         yield self._verifyObjectResourceCount("user01", 1)
         groupsToRefresh = yield groupCacher.groupsToRefresh(self.transactionUnderTest())
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150630/840aefac/attachment-0001.html>


More information about the calendarserver-changes mailing list