<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[14929] CalendarServer/trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/14929">14929</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-06-29 13:48:15 -0700 (Mon, 29 Jun 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Fix recurrence splitting for all-day and floating events.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkdocExtensionscaldavrecursplittxt">CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt</a></li>
<li><a href="#CalendarServertrunkdocExtensionscaldavrecursplitxml">CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml</a></li>
<li><a href="#CalendarServertrunkrequirementsdevtxt">CalendarServer/trunk/requirements-dev.txt</a></li>
<li><a href="#CalendarServertrunktwistedcaldavicalpy">CalendarServer/trunk/twistedcaldav/ical.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoreschedulingicalsplitterpy">CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoresqlpy">CalendarServer/trunk/txdav/caldav/datastore/sql.py</a></li>
<li><a href="#CalendarServertrunktxdavcaldavdatastoretesttest_sqlpy">CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkdocExtensionscaldavrecursplittxt"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt (14928 => 14929)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt        2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/doc/Extensions/caldav-recursplit.txt        2015-06-29 20:48:15 UTC (rev 14929)
</span><span class="lines">@@ -4,11 +4,11 @@
</span><span class="cx"> 
</span><span class="cx">                                                                 C. Daboo
</span><span class="cx">                                                                    Apple
</span><del>-                                                        October 30, 2014
</del><ins>+                                                           June 26, 2015
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">              Smart Splitting of Recurring Events in CalDAV
</span><del>-                          caldav-recursplit-01
</del><ins>+                          caldav-recursplit-02
</ins><span class="cx"> 
</span><span class="cx"> Abstract
</span><span class="cx"> 
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx">    1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   1
</span><span class="cx">    2.  Conventions Used in This Document . . . . . . . . . . . . . .   2
</span><span class="cx">    3.  New behavior  . . . . . . . . . . . . . . . . . . . . . . . .   3
</span><del>-     3.1.  Example . . . . . . . . . . . . . . . . . . . . . . . . .   5
</del><ins>+     3.1.  Example . . . . . . . . . . . . . . . . . . . . . . . . .   6
</ins><span class="cx">    4.  Server Initiated Splitting  . . . . . . . . . . . . . . . . .   8
</span><span class="cx">    5.  Security Considerations . . . . . . . . . . . . . . . . . . .   8
</span><span class="cx">    6.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .   8
</span><span class="lines">@@ -53,9 +53,9 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-Daboo                      Expires May 3, 2015                  [Page 1]
</del><ins>+Daboo                   Expires December 28, 2015               [Page 1]
</ins><span class="cx"> 
</span><del>-                       CalDAV Recurrence Splitting          October 2014
</del><ins>+                       CalDAV Recurrence Splitting             June 2015
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">    instances from that point onwards.  Typically this is done by
</span><span class="lines">@@ -109,9 +109,9 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-Daboo                      Expires May 3, 2015                  [Page 2]
</del><ins>+Daboo                   Expires December 28, 2015               [Page 2]
</ins><span class="cx"> 
</span><del>-                       CalDAV Recurrence Splitting          October 2014
</del><ins>+                       CalDAV Recurrence Splitting             June 2015
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 3.  New behavior
</span><span class="lines">@@ -128,16 +128,30 @@
</span><span class="cx"> 
</span><span class="cx">    1.  &quot;action&quot; set to the value &quot;split&quot; - REQUIRED
</span><span class="cx"> 
</span><del>-   2.  &quot;rid&quot; set to an iCalendar format DATE-TIME value in UTC
-       (&quot;YYYYMMDDTHHMMSSZ&quot; style format) - REQUIRED
</del><ins>+   2.  &quot;rid&quot; set to an iCalendar format DATE or DATE-TIME value (with
+       format choice determined as per description below) - REQUIRED
</ins><span class="cx"> 
</span><span class="cx">    3.  &quot;uid&quot; set to an iCalendar UID property value - OPTIONAL
</span><span class="cx"> 
</span><span class="cx">    The &quot;action&quot; parameter is used to distinguish this operation from
</span><span class="cx">    others that might be defined in the future for calendar object
</span><del>-   resources.  The &quot;rid&quot; parameter specified the UTC date-time where the
-   split is to occur.  The actual split occurs at the next recurrence
-   instance on or after the &quot;rid&quot; parameter value - the &quot;split point&quot;.
</del><ins>+   resources.
+
+   The &quot;rid&quot; parameter specifies the date or date-time where the split
+   is to occur.  The actual split occurs at the next recurrence instance
+   on or after the &quot;rid&quot; parameter value - the &quot;split point&quot;.  The &quot;rid&quot;
+   parameter value is an iCalendar DATE or DATE-TIME value that follows
+   that matched the event's DTSTART value as follows:
+
+   +---------------------------+--------------------+------------------+
+   | DTSTART value             | rid value          | rid example      |
+   +---------------------------+--------------------+------------------+
+   | DATE                      | DATE               | 20150626         |
+   | DATE-TIME UTC             | DATE-TIME UTC      | 20150626T120000Z |
+   | DATE-TIME local+time zone | DATE-TIME UTC      | 20150626T120000Z |
+   | DATE-TIME floating        | DATE-TIME floating | 20150626T120000  |
+   +---------------------------+--------------------+------------------+
+
</ins><span class="cx">    The optional &quot;uid&quot; parameter can be used by the client to specify the
</span><span class="cx">    iCalendar UID property value used in the new calendar object resource
</span><span class="cx">    created by the server.  In the absence of the &quot;uid&quot; parameter, the
</span><span class="lines">@@ -145,9 +159,17 @@
</span><span class="cx">    resource.
</span><span class="cx"> 
</span><span class="cx">    Clients MUST include both &quot;action&quot; and &quot;rid&quot; parameters in the POST
</span><del>-   request and MUST ensure a valid date-time value is used.  The date-
-   time value MUST NOT be earlier than the start time of the first
</del><ins>+   request and MUST ensure a valid date-time value is used.  The &quot;rid&quot;
+   parameter value MUST NOT be earlier than the start time of the first
</ins><span class="cx">    instance of the recurrence set, and it MUST NOT be later than the
</span><ins>+
+
+
+Daboo                   Expires December 28, 2015               [Page 3]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
</ins><span class="cx">    start time of the last instance of the recurrence set.  If the &quot;rid&quot;
</span><span class="cx">    parameter value is not of the correct format or missing, the server
</span><span class="cx">    MUST return a DAV:error response with the CALDAV:valid-rid-parameter
</span><span class="lines">@@ -162,14 +184,6 @@
</span><span class="cx">    too long as per reasonable requirements), then it MUST return a
</span><span class="cx">    DAV:error response with the CS:invalid-split pre-condition code.
</span><span class="cx"> 
</span><del>-
-
-
-Daboo                      Expires May 3, 2015                  [Page 3]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
</del><span class="cx">    Clients MAY include an HTTP &quot;Prefer&quot; request header including the
</span><span class="cx">    value &quot;return=representation&quot; (see [RFC7240]).  That instructs the
</span><span class="cx">    server to return a WebDAV multistatus response containing two
</span><span class="lines">@@ -203,6 +217,15 @@
</span><span class="cx">            by subtracting the number of instances prior to the split
</span><span class="cx">            point.
</span><span class="cx"> 
</span><ins>+
+
+
+
+Daboo                   Expires December 28, 2015               [Page 4]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
</ins><span class="cx">        E.  The &quot;DTSTART&quot; property of the master instance is adjusted to
</span><span class="cx">            the value of the first instance of the &quot;RRULE&quot; on or after
</span><span class="cx">            the split point, or, in the absence of an &quot;RRULE&quot;, to the
</span><span class="lines">@@ -219,16 +242,10 @@
</span><span class="cx">        C.  Any &quot;RRULE&quot; property that only generates instances on or
</span><span class="cx">            after the split point is removed.
</span><span class="cx"> 
</span><del>-
-
-Daboo                      Expires May 3, 2015                  [Page 4]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
</del><span class="cx">        D.  Any remaining &quot;RRULE&quot; property has an &quot;UNTIL&quot; value applied,
</span><del>-           with the until value being one second less than the split
-           point.
</del><ins>+           with the until value being one second (for a &quot;rid&quot; DATE-TIME
+           value) or one day (for a &quot;rid&quot; DATE value) less than the
+           split point.
</ins><span class="cx"> 
</span><span class="cx">        E.  The &quot;UID&quot; property of all components is changed to (the same)
</span><span class="cx">            new value.
</span><span class="lines">@@ -256,6 +273,15 @@
</span><span class="cx">        attendee with both the modified (old) resource data and the new
</span><span class="cx">        resource.  This will likely result in loss of per-attendee data
</span><span class="cx">        such as alarms (though the participation status might be
</span><ins>+
+
+
+
+Daboo                   Expires December 28, 2015               [Page 5]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
</ins><span class="cx">        preserved if the calendar user agent processing the new iTIP
</span><span class="cx">        message for the new resource allows it).
</span><span class="cx"> 
</span><span class="lines">@@ -272,16 +298,6 @@
</span><span class="cx">    Assume the following iCalendar data is stored in the resource with
</span><span class="cx">    URI &quot;/event.ics&quot;:
</span><span class="cx"> 
</span><del>-
-
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 5]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
</del><span class="cx">    BEGIN:VCALENDAR
</span><span class="cx">    PRODID:-//Example Inc.//Example Calendar//EN
</span><span class="cx">    VERSION:2.0
</span><span class="lines">@@ -314,6 +330,14 @@
</span><span class="cx">    Content-Type: text/xml
</span><span class="cx">    Content-Length: xxxx
</span><span class="cx"> 
</span><ins>+
+
+
+Daboo                   Expires December 28, 2015               [Page 6]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
</ins><span class="cx">    &lt;?xml version='1.0' encoding='UTF-8'?&gt;
</span><span class="cx">    &lt;multistatus xmlns='DAV:'&gt;
</span><span class="cx">      &lt;response&gt;
</span><span class="lines">@@ -330,14 +354,6 @@
</span><span class="cx">    DTSTART:20140110T120000Z
</span><span class="cx">    DURATION:PT1H
</span><span class="cx">    DTSTAMP:20140110T135358Z
</span><del>-
-
-
-Daboo                      Expires May 3, 2015                  [Page 6]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
</del><span class="cx">    RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:8DE45ECB-8145-
</span><span class="cx">     4AEC-B3E1-11A9DB22A578
</span><span class="cx">    RRULE:FREQ=DAILY;COUNT=11
</span><span class="lines">@@ -370,6 +386,14 @@
</span><span class="cx">    END:VEVENT
</span><span class="cx">    END:VCALENDAR
</span><span class="cx">    &lt;/calendar-data&gt;
</span><ins>+
+
+
+Daboo                   Expires December 28, 2015               [Page 7]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
</ins><span class="cx">          &lt;/prop&gt;
</span><span class="cx">          &lt;status&gt;HTTP/1.1 200 OK&lt;/status&gt;
</span><span class="cx">        &lt;/propstat&gt;
</span><span class="lines">@@ -386,14 +410,6 @@
</span><span class="cx">    &quot;RELTYPE&quot; parameter set to &quot;X-CALENDARSERVER-RECURRENCE-SET&quot; and a
</span><span class="cx">    value set to a new &quot;UID&quot; value.
</span><span class="cx"> 
</span><del>-
-
-
-Daboo                      Expires May 3, 2015                  [Page 7]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
</del><span class="cx"> 4.  Server Initiated Splitting
</span><span class="cx"> 
</span><span class="cx">    Servers can automatically split events that have already been stored
</span><span class="lines">@@ -426,6 +442,14 @@
</span><span class="cx">               &quot;Calendaring Extensions to WebDAV (CalDAV)&quot;, RFC 4791,
</span><span class="cx">               March 2007.
</span><span class="cx"> 
</span><ins>+
+
+
+Daboo                   Expires December 28, 2015               [Page 8]
+
+                       CalDAV Recurrence Splitting             June 2015
+
+
</ins><span class="cx">    [RFC5545]  Desruisseaux, B., &quot;Internet Calendaring and Scheduling
</span><span class="cx">               Core Object Specification (iCalendar)&quot;, RFC 5545,
</span><span class="cx">               September 2009.
</span><span class="lines">@@ -439,17 +463,6 @@
</span><span class="cx"> 
</span><span class="cx">    [RFC7240]  Snell, J., &quot;Prefer Header for HTTP&quot;, RFC 7240, June 2014.
</span><span class="cx"> 
</span><del>-
-
-
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 8]
-
-                       CalDAV Recurrence Splitting          October 2014
-
-
</del><span class="cx"> Appendix A.  Acknowledgments
</span><span class="cx"> 
</span><span class="cx">    This specification is the result of discussions between the Apple
</span><span class="lines">@@ -457,6 +470,14 @@
</span><span class="cx"> 
</span><span class="cx"> Appendix B.  Change History
</span><span class="cx"> 
</span><ins>+   Changes since -02
+
+   1.  Clarify that rid query parameter value matches the event DTSTART
+       value type using the UNTIL &quot;rules&quot;
+
+   2.  Clarify that earlier event uses an UNTIL one second or one day
+       less that the &quot;rid&quot; value depending on the value type.
+
</ins><span class="cx">    Changes since -01
</span><span class="cx"> 
</span><span class="cx">    1.  Added &quot;uid&quot; query parameter to POST request
</span><span class="lines">@@ -480,25 +501,4 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Daboo                      Expires May 3, 2015                  [Page 9]
</del><ins>+Daboo                   Expires December 28, 2015               [Page 9]
</ins></span></pre></div>
<a id="CalendarServertrunkdocExtensionscaldavrecursplitxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml (14928 => 14929)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml        2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/doc/Extensions/caldav-recursplit.xml        2015-06-29 20:48:15 UTC (rev 14929)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> &lt;?rfc compact=&quot;yes&quot;?&gt;
</span><span class="cx"> &lt;?rfc subcompact=&quot;no&quot;?&gt;
</span><span class="cx"> &lt;?rfc private=&quot;Calendar Server Extension&quot;?&gt;
</span><del>-&lt;rfc ipr=&quot;none&quot; docName='caldav-recursplit-01'&gt;
</del><ins>+&lt;rfc ipr=&quot;none&quot; docName='caldav-recursplit-02'&gt;
</ins><span class="cx">     &lt;front&gt;
</span><span class="cx">         &lt;title abbrev=&quot;CalDAV Recurrence Splitting&quot;&gt;Smart Splitting of Recurring Events in CalDAV&lt;/title&gt; 
</span><span class="cx">         &lt;author initials=&quot;C.&quot; surname=&quot;Daboo&quot; fullname=&quot;Cyrus Daboo&quot;&gt;
</span><span class="lines">@@ -79,12 +79,37 @@
</span><span class="cx">           &lt;t&gt;To split an existing calendar object resource containing a recurring event, a client issues an HTTP POST resource with the request-uri set to the URI of the calendar object resource. The client also includes the following two URI query parameters, and one optional one:
</span><span class="cx">             &lt;list style='numbers'&gt;
</span><span class="cx">               &lt;t&gt;&quot;action&quot; set to the value &quot;split&quot; - REQUIRED&lt;/t&gt;
</span><del>-              &lt;t&gt;&quot;rid&quot; set to an iCalendar format DATE-TIME value in UTC (&quot;YYYYMMDDTHHMMSSZ&quot; style format) - REQUIRED&lt;/t&gt;
</del><ins>+              &lt;t&gt;&quot;rid&quot; set to an iCalendar format DATE or DATE-TIME value (with format choice determined as per description below) - REQUIRED&lt;/t&gt;
</ins><span class="cx">               &lt;t&gt;&quot;uid&quot; set to an iCalendar UID property value - OPTIONAL&lt;/t&gt;
</span><span class="cx">             &lt;/list&gt;
</span><del>-            The &quot;action&quot; parameter is used to distinguish this operation from others that might be defined in the future for calendar object resources. The &quot;rid&quot; parameter specified the UTC date-time where the split is to occur. The actual split occurs at the next recurrence instance on or after the &quot;rid&quot; parameter value - the &quot;split point&quot;. The optional &quot;uid&quot; parameter can be used by the client to specify the iCalendar UID property value used in the new calendar object resource created by the server. In the absence of the &quot;uid&quot; parameter, the server will itself generate the UID value for the new calendar object resource.&lt;/t&gt;
</del><ins>+            &lt;/t&gt;
+            &lt;t&gt;The &quot;action&quot; parameter is used to distinguish this operation from others that might be defined in the future for calendar object resources.&lt;/t&gt;
+            &lt;t&gt;The &quot;rid&quot; parameter specifies the date or date-time where the split is to occur. The actual split occurs at the next recurrence instance on or after the &quot;rid&quot; parameter value - the &quot;split point&quot;. The &quot;rid&quot; parameter value is an iCalendar DATE or DATE-TIME value that follows that matched the event's DTSTART value as follows:&lt;/t&gt;
+            &lt;texttable&gt;
+              &lt;ttcol&gt;DTSTART value&lt;/ttcol&gt;
+              &lt;ttcol&gt;rid value&lt;/ttcol&gt;
+              &lt;ttcol&gt;rid example&lt;/ttcol&gt;
+
+              &lt;c&gt;DATE&lt;/c&gt;
+              &lt;c&gt;DATE&lt;/c&gt;
+              &lt;c&gt;20150626&lt;/c&gt;
+
+              &lt;c&gt;DATE-TIME UTC&lt;/c&gt;
+              &lt;c&gt;DATE-TIME UTC&lt;/c&gt;
+              &lt;c&gt;20150626T120000Z&lt;/c&gt;
+
+              &lt;c&gt;DATE-TIME local+time zone&lt;/c&gt;
+              &lt;c&gt;DATE-TIME UTC&lt;/c&gt;
+              &lt;c&gt;20150626T120000Z&lt;/c&gt;
+
+              &lt;c&gt;DATE-TIME floating&lt;/c&gt;
+              &lt;c&gt;DATE-TIME floating&lt;/c&gt;
+              &lt;c&gt;20150626T120000&lt;/c&gt;
+
+            &lt;/texttable&gt;
+            &lt;t&gt;The optional &quot;uid&quot; parameter can be used by the client to specify the iCalendar UID property value used in the new calendar object resource created by the server. In the absence of the &quot;uid&quot; parameter, the server will itself generate the UID value for the new calendar object resource.&lt;/t&gt;
</ins><span class="cx">             &lt;t&gt;
</span><del>-            Clients MUST include both &quot;action&quot; and &quot;rid&quot; parameters in the POST request and MUST ensure a valid date-time value is used. The date-time value MUST NOT be earlier than the start time of the first instance of the recurrence set, and it MUST NOT be later than the start time of the last instance of the recurrence set. If the &quot;rid&quot; parameter value is not of the correct format or missing, the server MUST return a DAV:error response with the CALDAV:valid-rid-parameter pre-condition code. If the &quot;rid&quot; parameter is valid, but outside of the allowed range, or the targeted calendar object resource is not recurring, then the server MUST return a DAV:error response with the CS:invalid-split pre-condition code. The server MUST reject any attempt by an attendee to split their copy of a scheduled calendar object resource - only organizers are allowed to split events. If the optional &quot;uid&quot; parameter is used by the c
 lient, and the server determines that the specified value is invalid (e.g., too short or too long as per reasonable requirements), then it MUST return a DAV:error response with the CS:invalid-split pre-condition code.
</del><ins>+            Clients MUST include both &quot;action&quot; and &quot;rid&quot; parameters in the POST request and MUST ensure a valid date-time value is used. The &quot;rid&quot; parameter value MUST NOT be earlier than the start time of the first instance of the recurrence set, and it MUST NOT be later than the start time of the last instance of the recurrence set. If the &quot;rid&quot; parameter value is not of the correct format or missing, the server MUST return a DAV:error response with the CALDAV:valid-rid-parameter pre-condition code. If the &quot;rid&quot; parameter is valid, but outside of the allowed range, or the targeted calendar object resource is not recurring, then the server MUST return a DAV:error response with the CS:invalid-split pre-condition code. The server MUST reject any attempt by an attendee to split their copy of a scheduled calendar object resource - only organizers are allowed to split events. If the optional &quot;uid&quot; parameter i
 s used by the client, and the server determines that the specified value is invalid (e.g., too short or too long as per reasonable requirements), then it MUST return a DAV:error response with the CS:invalid-split pre-condition code.
</ins><span class="cx">           &lt;/t&gt;
</span><span class="cx">           &lt;t&gt;
</span><span class="cx">             Clients MAY include an HTTP &quot;Prefer&quot; request header including the value &quot;return=representation&quot; (see &lt;xref target='RFC7240'/&gt;). That instructs the server to return a WebDAV multistatus response containing two responses: one for the targeted resource and one for the new resource created as a result of the split. The multistatus response MUST include the DAV:getetag and CALDAV:calendar-data properties for each resource. In the absence of the &quot;Prefer:return=representation&quot; request header, the server MUST return an HTTP &quot;Split-Component-URL&quot; response header whose value is the URI of the new resource created as a result of the split.
</span><span class="lines">@@ -107,7 +132,7 @@
</span><span class="cx">                   &lt;t&gt;Any overridden components with a &quot;RECURRENCE-ID&quot; property value on or after the split point are removed.&lt;/t&gt;
</span><span class="cx">                   &lt;t&gt;Any &quot;RDATE&quot; or &quot;EXDATE&quot; property values on or after the split point are removed.&lt;/t&gt;
</span><span class="cx">                   &lt;t&gt;Any &quot;RRULE&quot; property that only generates instances on or after the split point is removed.&lt;/t&gt;
</span><del>-                  &lt;t&gt;Any remaining &quot;RRULE&quot; property has an &quot;UNTIL&quot; value applied, with the until value being one second less than the split point.&lt;/t&gt;
</del><ins>+                  &lt;t&gt;Any remaining &quot;RRULE&quot; property has an &quot;UNTIL&quot; value applied, with the until value being one second (for a &quot;rid&quot; DATE-TIME value) or one day (for a &quot;rid&quot; DATE value) less than the split point.&lt;/t&gt;
</ins><span class="cx">                   &lt;t&gt;The &quot;UID&quot; property of all components is changed to (the same) new value.&lt;/t&gt;
</span><span class="cx">                   &lt;t&gt;Attendee participation status MUST NOT be changed.&lt;/t&gt;
</span><span class="cx">                 &lt;/list&gt;
</span><span class="lines">@@ -259,6 +284,12 @@
</span><span class="cx">             &lt;/t&gt;
</span><span class="cx">         &lt;/section&gt;
</span><span class="cx">         &lt;section title='Change History'&gt;
</span><ins>+          &lt;t&gt;Changes since -02
+            &lt;list style='numbers'&gt;
+              &lt;t&gt;Clarify that rid query parameter value matches the event DTSTART value type using the UNTIL &quot;rules&quot;&lt;/t&gt;
+              &lt;t&gt;Clarify that earlier event uses an UNTIL one second or one day less that the &quot;rid&quot; value depending on the value type.&lt;/t&gt;
+            &lt;/list&gt;
+          &lt;/t&gt;
</ins><span class="cx">           &lt;t&gt;Changes since -01
</span><span class="cx">             &lt;list style='numbers'&gt;
</span><span class="cx">               &lt;t&gt;Added &quot;uid&quot; query parameter to POST request&lt;/t&gt;
</span></span></pre></div>
<a id="CalendarServertrunkrequirementsdevtxt"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/requirements-dev.txt (14928 => 14929)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-dev.txt        2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/requirements-dev.txt        2015-06-29 20:48:15 UTC (rev 14929)
</span><span class="lines">@@ -8,4 +8,4 @@
</span><span class="cx"> q
</span><span class="cx"> tl.eggdeps
</span><span class="cx"> --editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVClientLibrary/trunk@14856#egg=CalDAVClientLibrary
</span><del>---editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@14920#egg=CalDAVTester
</del><ins>+--editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@14928#egg=CalDAVTester
</ins></span></pre></div>
<a id="CalendarServertrunktwistedcaldavicalpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/ical.py (14928 => 14929)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/ical.py        2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/twistedcaldav/ical.py        2015-06-29 20:48:15 UTC (rev 14929)
</span><span class="lines">@@ -1255,7 +1255,10 @@
</span><span class="cx">                     rrule.setUseUntil(True)
</span><span class="cx">                     rrule.setUseCount(False)
</span><span class="cx">                     until = rid.duplicate()
</span><del>-                    until.offsetSeconds(-1)
</del><ins>+                    if until.isDateOnly():
+                        until.offsetDay(-1)
+                    else:
+                        until.offsetSeconds(-1)
</ins><span class="cx">                     rrule.setUntil(until)
</span><span class="cx"> 
</span><span class="cx">             # Remove any RDATEs or EXDATEs in the future
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoreschedulingicalsplitterpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py (14928 => 14929)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py        2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling/icalsplitter.py        2015-06-29 20:48:15 UTC (rev 14929)
</span><span class="lines">@@ -139,6 +139,15 @@
</span><span class="cx">             # where the Organizer event has L{willSplit} == C{True}
</span><span class="cx">             rid = break_point if allow_past_the_end else None
</span><span class="cx"> 
</span><ins>+        if rid is not None:
+            # rid value type must match
+            dtstart = ical.mainComponent().propertyValue(&quot;DTSTART&quot;)
+            if dtstart.isDateOnly():
+                rid.setDateOnly(True)
+            elif dtstart.floating():
+                rid.setTimezoneID(None)
+
+
</ins><span class="cx">         return rid
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py (14928 => 14929)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/sql.py        2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py        2015-06-29 20:48:15 UTC (rev 14929)
</span><span class="lines">@@ -5153,6 +5153,19 @@
</span><span class="cx">         if organizer is not None and organizerAddress.record.uid != self.calendar().ownerHome().uid():
</span><span class="cx">             raise InvalidSplit(&quot;Only organizers can split events.&quot;)
</span><span class="cx"> 
</span><ins>+        # rid value type must match
+        dtstart = component.mainComponent().propertyValue(&quot;DTSTART&quot;)
+        if dtstart.isDateOnly():
+            if not rid.isDateOnly():
+                # We ought to reject this but for now we will fix it
+                rid.setDateOnly(True)
+        elif dtstart.floating():
+            if not rid.floating() or rid.isDateOnly():
+                raise InvalidSplit(&quot;rid parameter value type must match DTSTART value type.&quot;)
+        else:
+            if rid.floating():
+                raise InvalidSplit(&quot;rid parameter value type must match DTSTART value type.&quot;)
+
</ins><span class="cx">         # Determine valid split point
</span><span class="cx">         splitter = iCalSplitter(1024, 14)
</span><span class="cx">         rid = splitter.whereSplit(component, break_point=rid, allow_past_the_end=False)
</span></span></pre></div>
<a id="CalendarServertrunktxdavcaldavdatastoretesttest_sqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py (14928 => 14929)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py        2015-06-29 20:46:25 UTC (rev 14928)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py        2015-06-29 20:48:15 UTC (rev 14929)
</span><span class="lines">@@ -3183,8 +3183,14 @@
</span><span class="cx"> 
</span><span class="cx">         self.now = DateTime.getNowUTC()
</span><span class="cx">         self.now.setHHMMSS(0, 0, 0)
</span><ins>+        self.nowDate = self.now.duplicate()
+        self.nowDate.setDateOnly(True)
+        self.nowFloating = self.now.duplicate()
+        self.nowFloating.setTimezoneID(None)
</ins><span class="cx"> 
</span><span class="cx">         self.subs[&quot;now&quot;] = self.now
</span><ins>+        self.subs[&quot;nowDate&quot;] = self.nowDate
+        self.subs[&quot;nowFloating&quot;] = self.nowFloating
</ins><span class="cx"> 
</span><span class="cx">         for i in range(30):
</span><span class="cx">             attrname = &quot;now_back%s&quot; % (i + 1,)
</span><span class="lines">@@ -3202,6 +3208,21 @@
</span><span class="cx">             getattr(self, attrname_1).offsetSeconds(-1)
</span><span class="cx">             self.subs[attrname_1] = getattr(self, attrname_1)
</span><span class="cx"> 
</span><ins>+            attrname = &quot;nowDate_back%s&quot; % (i + 1,)
+            setattr(self, attrname, self.nowDate.duplicate())
+            getattr(self, attrname).offsetDay(-(i + 1))
+            self.subs[attrname] = getattr(self, attrname)
+
+            attrname = &quot;nowFloating_back%s&quot; % (i + 1,)
+            setattr(self, attrname, self.nowFloating.duplicate())
+            getattr(self, attrname).offsetDay(-(i + 1))
+            self.subs[attrname] = getattr(self, attrname)
+
+            attrname_1 = &quot;nowFloating_back%s_1&quot; % (i + 1,)
+            setattr(self, attrname_1, getattr(self, attrname).duplicate())
+            getattr(self, attrname_1).offsetSeconds(-1)
+            self.subs[attrname_1] = getattr(self, attrname_1)
+
</ins><span class="cx">         for i in range(30):
</span><span class="cx">             attrname = &quot;now_fwd%s&quot; % (i + 1,)
</span><span class="cx">             setattr(self, attrname, self.now.duplicate())
</span><span class="lines">@@ -3213,6 +3234,16 @@
</span><span class="cx">             getattr(self, attrname_12h).offsetHours(12)
</span><span class="cx">             self.subs[attrname_12h] = getattr(self, attrname_12h)
</span><span class="cx"> 
</span><ins>+            attrname = &quot;nowDate_fwd%s&quot; % (i + 1,)
+            setattr(self, attrname, self.nowDate.duplicate())
+            getattr(self, attrname).offsetDay(i + 1)
+            self.subs[attrname] = getattr(self, attrname)
+
+            attrname = &quot;nowFloating_fwd%s&quot; % (i + 1,)
+            setattr(self, attrname, self.nowFloating.duplicate())
+            getattr(self, attrname).offsetDay(i + 1)
+            self.subs[attrname] = getattr(self, attrname)
+
</ins><span class="cx">         self.patch(config, &quot;MaxAllowedInstances&quot;, 500)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -3453,6 +3484,428 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><ins>+    def test_calendarObjectSplit_AllDay(self):
+        &quot;&quot;&quot;
+        Test that (manual) splitting of all-day calendar objects works.
+        &quot;&quot;&quot;
+
+        self.patch(config.Scheduling.Options.Splitting, &quot;Enabled&quot;, False)
+        self.patch(config.Scheduling.Options.Splitting, &quot;Size&quot;, 1024)
+        self.patch(config.Scheduling.Options.Splitting, &quot;PastDays&quot;, 14)
+
+        # Create one event that will split
+        calendar = yield self.calendarUnderTest(name=&quot;calendar&quot;, home=&quot;user01&quot;)
+
+        data = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:%(nowDate_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+ATTENDEE:mailto:user3@example.org
+ATTENDEE:mailto:user4@example.org
+ATTENDEE:mailto:user5@example.org
+ATTENDEE:mailto:user6@example.org
+ATTENDEE:mailto:user7@example.org
+ATTENDEE:mailto:user8@example.org
+ATTENDEE:mailto:user9@example.org
+ATTENDEE:mailto:user10@example.org
+ATTENDEE:mailto:user11@example.org
+ATTENDEE:mailto:user12@example.org
+ATTENDEE:mailto:user13@example.org
+ATTENDEE:mailto:user14@example.org
+ATTENDEE:mailto:user15@example.org
+ATTENDEE:mailto:user16@example.org
+ATTENDEE:mailto:user17@example.org
+ATTENDEE:mailto:user18@example.org
+ATTENDEE:mailto:user19@example.org
+ATTENDEE:mailto:user20@example.org
+ATTENDEE:mailto:user21@example.org
+ATTENDEE:mailto:user22@example.org
+ATTENDEE:mailto:user23@example.org
+ATTENDEE:mailto:user24@example.org
+ATTENDEE:mailto:user25@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1@example.org
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back25)s
+DTSTART;VALUE=DATE:%(nowDate_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1@example.org
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back24)s
+DTSTART;VALUE=DATE:%(nowDate_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1@example.org
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        data_future = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:%(nowDate_back14)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+ATTENDEE:mailto:user3@example.org
+ATTENDEE:mailto:user4@example.org
+ATTENDEE:mailto:user5@example.org
+ATTENDEE:mailto:user6@example.org
+ATTENDEE:mailto:user7@example.org
+ATTENDEE:mailto:user8@example.org
+ATTENDEE:mailto:user9@example.org
+ATTENDEE:mailto:user10@example.org
+ATTENDEE:mailto:user11@example.org
+ATTENDEE:mailto:user12@example.org
+ATTENDEE:mailto:user13@example.org
+ATTENDEE:mailto:user14@example.org
+ATTENDEE:mailto:user15@example.org
+ATTENDEE:mailto:user16@example.org
+ATTENDEE:mailto:user17@example.org
+ATTENDEE:mailto:user18@example.org
+ATTENDEE:mailto:user19@example.org
+ATTENDEE:mailto:user20@example.org
+ATTENDEE:mailto:user21@example.org
+ATTENDEE:mailto:user22@example.org
+ATTENDEE:mailto:user23@example.org
+ATTENDEE:mailto:user24@example.org
+ATTENDEE:mailto:user25@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        data_past = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:%(uid)s
+DTSTART;VALUE=DATE:%(nowDate_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+ATTENDEE:mailto:user3@example.org
+ATTENDEE:mailto:user4@example.org
+ATTENDEE:mailto:user5@example.org
+ATTENDEE:mailto:user6@example.org
+ATTENDEE:mailto:user7@example.org
+ATTENDEE:mailto:user8@example.org
+ATTENDEE:mailto:user9@example.org
+ATTENDEE:mailto:user10@example.org
+ATTENDEE:mailto:user11@example.org
+ATTENDEE:mailto:user12@example.org
+ATTENDEE:mailto:user13@example.org
+ATTENDEE:mailto:user14@example.org
+ATTENDEE:mailto:user15@example.org
+ATTENDEE:mailto:user16@example.org
+ATTENDEE:mailto:user17@example.org
+ATTENDEE:mailto:user18@example.org
+ATTENDEE:mailto:user19@example.org
+ATTENDEE:mailto:user20@example.org
+ATTENDEE:mailto:user21@example.org
+ATTENDEE:mailto:user22@example.org
+ATTENDEE:mailto:user23@example.org
+ATTENDEE:mailto:user24@example.org
+ATTENDEE:mailto:user25@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY;UNTIL=%(nowDate_back15)s
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back25)s
+DTSTART;VALUE=DATE:%(nowDate_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID;VALUE=DATE:%(nowDate_back24)s
+DTSTART;VALUE=DATE:%(nowDate_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        component = Component.fromString(data % self.subs)
+        cobj = yield calendar.createCalendarObjectWithName(&quot;data1.ics&quot;, component)
+        self.assertFalse(hasattr(cobj, &quot;_workItems&quot;))
+        yield self.commit()
+
+        w = schema.CALENDAR_OBJECT_SPLITTER_WORK
+        rows = yield Select(
+            [w.RESOURCE_ID, ],
+            From=w
+        ).on(self.transactionUnderTest())
+        self.assertEqual(len(rows), 0)
+        yield self.abort()
+
+        # Do manual split
+        cobj = yield self.calendarObjectUnderTest(name=&quot;data1.ics&quot;, calendar_name=&quot;calendar&quot;, home=&quot;user01&quot;)
+        will = yield cobj.willSplit()
+        self.assertTrue(will)
+
+        yield cobj.split()
+        yield self.commit()
+
+        ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails(&quot;user01&quot;)
+
+        title = &quot;temp&quot;
+        relsubs = dict(self.subs)
+        relsubs[&quot;uid&quot;] = pastUID
+        relsubs[&quot;relID&quot;] = relID
+        self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, &quot;Failed future: %s %s&quot; % (title, diff_iCalStrs(ical_future, data_future % relsubs)))
+        self.assertEqual(normalize_iCalStr(ical_past), normalize_iCalStr(data_past) % relsubs, &quot;Failed past: %s %s&quot; % (title, diff_iCalStrs(ical_past, data_past % relsubs)))
+
+
+    @inlineCallbacks
+    def test_calendarObjectSplit_Floating(self):
+        &quot;&quot;&quot;
+        Test that (manual) splitting of floating calendar objects works.
+        &quot;&quot;&quot;
+
+        self.patch(config.Scheduling.Options.Splitting, &quot;Enabled&quot;, False)
+        self.patch(config.Scheduling.Options.Splitting, &quot;Size&quot;, 1024)
+        self.patch(config.Scheduling.Options.Splitting, &quot;PastDays&quot;, 14)
+
+        # Create one event that will split
+        calendar = yield self.calendarUnderTest(name=&quot;calendar&quot;, home=&quot;user01&quot;)
+
+        data = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:%(nowFloating_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+ATTENDEE:mailto:user3@example.org
+ATTENDEE:mailto:user4@example.org
+ATTENDEE:mailto:user5@example.org
+ATTENDEE:mailto:user6@example.org
+ATTENDEE:mailto:user7@example.org
+ATTENDEE:mailto:user8@example.org
+ATTENDEE:mailto:user9@example.org
+ATTENDEE:mailto:user10@example.org
+ATTENDEE:mailto:user11@example.org
+ATTENDEE:mailto:user12@example.org
+ATTENDEE:mailto:user13@example.org
+ATTENDEE:mailto:user14@example.org
+ATTENDEE:mailto:user15@example.org
+ATTENDEE:mailto:user16@example.org
+ATTENDEE:mailto:user17@example.org
+ATTENDEE:mailto:user18@example.org
+ATTENDEE:mailto:user19@example.org
+ATTENDEE:mailto:user20@example.org
+ATTENDEE:mailto:user21@example.org
+ATTENDEE:mailto:user22@example.org
+ATTENDEE:mailto:user23@example.org
+ATTENDEE:mailto:user24@example.org
+ATTENDEE:mailto:user25@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1@example.org
+RRULE:FREQ=DAILY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:%(nowFloating_back25)s
+DTSTART:%(nowFloating_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1@example.org
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:%(nowFloating_back24)s
+DTSTART:%(nowFloating_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user1@example.org
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        data_future = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:%(nowFloating_back14)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+ATTENDEE:mailto:user3@example.org
+ATTENDEE:mailto:user4@example.org
+ATTENDEE:mailto:user5@example.org
+ATTENDEE:mailto:user6@example.org
+ATTENDEE:mailto:user7@example.org
+ATTENDEE:mailto:user8@example.org
+ATTENDEE:mailto:user9@example.org
+ATTENDEE:mailto:user10@example.org
+ATTENDEE:mailto:user11@example.org
+ATTENDEE:mailto:user12@example.org
+ATTENDEE:mailto:user13@example.org
+ATTENDEE:mailto:user14@example.org
+ATTENDEE:mailto:user15@example.org
+ATTENDEE:mailto:user16@example.org
+ATTENDEE:mailto:user17@example.org
+ATTENDEE:mailto:user18@example.org
+ATTENDEE:mailto:user19@example.org
+ATTENDEE:mailto:user20@example.org
+ATTENDEE:mailto:user21@example.org
+ATTENDEE:mailto:user22@example.org
+ATTENDEE:mailto:user23@example.org
+ATTENDEE:mailto:user24@example.org
+ATTENDEE:mailto:user25@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        data_past = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:%(uid)s
+DTSTART:%(nowFloating_back30)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+ATTENDEE:mailto:user3@example.org
+ATTENDEE:mailto:user4@example.org
+ATTENDEE:mailto:user5@example.org
+ATTENDEE:mailto:user6@example.org
+ATTENDEE:mailto:user7@example.org
+ATTENDEE:mailto:user8@example.org
+ATTENDEE:mailto:user9@example.org
+ATTENDEE:mailto:user10@example.org
+ATTENDEE:mailto:user11@example.org
+ATTENDEE:mailto:user12@example.org
+ATTENDEE:mailto:user13@example.org
+ATTENDEE:mailto:user14@example.org
+ATTENDEE:mailto:user15@example.org
+ATTENDEE:mailto:user16@example.org
+ATTENDEE:mailto:user17@example.org
+ATTENDEE:mailto:user18@example.org
+ATTENDEE:mailto:user19@example.org
+ATTENDEE:mailto:user20@example.org
+ATTENDEE:mailto:user21@example.org
+ATTENDEE:mailto:user22@example.org
+ATTENDEE:mailto:user23@example.org
+ATTENDEE:mailto:user24@example.org
+ATTENDEE:mailto:user25@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+RRULE:FREQ=DAILY;UNTIL=%(nowFloating_back14_1)s
+SEQUENCE:1
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID:%(nowFloating_back25)s
+DTSTART:%(nowFloating_back25)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+END:VEVENT
+BEGIN:VEVENT
+UID:%(uid)s
+RECURRENCE-ID:%(nowFloating_back24)s
+DTSTART:%(nowFloating_back24)s
+DURATION:P1D
+ATTENDEE:mailto:user1@example.org
+ATTENDEE:mailto:user2@example.org
+DTSTAMP:20051222T210507Z
+ORGANIZER;SCHEDULE-AGENT=NONE;SCHEDULE-STATUS=5.3:mailto:user1@example.org
+RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
+SEQUENCE:1
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        component = Component.fromString(data % self.subs)
+        cobj = yield calendar.createCalendarObjectWithName(&quot;data1.ics&quot;, component)
+        self.assertFalse(hasattr(cobj, &quot;_workItems&quot;))
+        yield self.commit()
+
+        w = schema.CALENDAR_OBJECT_SPLITTER_WORK
+        rows = yield Select(
+            [w.RESOURCE_ID, ],
+            From=w
+        ).on(self.transactionUnderTest())
+        self.assertEqual(len(rows), 0)
+        yield self.abort()
+
+        # Do manual split
+        cobj = yield self.calendarObjectUnderTest(name=&quot;data1.ics&quot;, calendar_name=&quot;calendar&quot;, home=&quot;user01&quot;)
+        will = yield cobj.willSplit()
+        self.assertTrue(will)
+
+        yield cobj.split()
+        yield self.commit()
+
+        ical_future, ical_past, pastUID, relID, _ignore_new_name = yield self._splitDetails(&quot;user01&quot;)
+
+        title = &quot;temp&quot;
+        relsubs = dict(self.subs)
+        relsubs[&quot;uid&quot;] = pastUID
+        relsubs[&quot;relID&quot;] = relID
+        self.assertEqual(normalize_iCalStr(ical_future), normalize_iCalStr(data_future) % relsubs, &quot;Failed future: %s %s&quot; % (title, diff_iCalStrs(ical_future, data_future % relsubs)))
+        self.assertEqual(normalize_iCalStr(ical_past), normalize_iCalStr(data_past) % relsubs, &quot;Failed past: %s %s&quot; % (title, diff_iCalStrs(ical_past, data_past % relsubs)))
+
+
+    @inlineCallbacks
</ins><span class="cx">     def test_calendarObjectSplit_work(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Test that splitting of calendar objects works.
</span><span class="lines">@@ -7649,7 +8102,54 @@
</span><span class="cx">         yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText(&quot;%(now_back14)s&quot; % self.subs), pastUID=&quot;12345-67890-existing&quot;), InvalidSplit)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    @inlineCallbacks
+    def test_calendarObjectSplit_splitat_wrong_value_type(self):
+        &quot;&quot;&quot;
+        Test that user triggered splitting of calendar objects does not work if wrong rid value type is used.
+        &quot;&quot;&quot;
</ins><span class="cx"> 
</span><ins>+        yield self._setupSplitAt()
+
+        # DTSTART DATE-TIME UTC/rid DATE
+        cal = yield self.calendarUnderTest(name=&quot;calendar&quot;, home=&quot;user02&quot;)
+        cobjs = yield cal.calendarObjects()
+        self.assertEqual(len(cobjs), 1)
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText(&quot;%(nowDate)s&quot; % self.subs)), InvalidSplit)
+
+        # DTSTART DATE-TIME UTC/rid DATE-TIME floating
+        yield self.failUnlessFailure(cobjs[0].splitAt(DateTime.parseText(&quot;%(nowFloating)s&quot; % self.subs)), InvalidSplit)
+
+        data_floating = &quot;&quot;&quot;BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-existing
+DTSTART:%(nowFloating)s
+DURATION:P1D
+DTSTAMP:20051222T210507Z
+RRULE:FREQ=DAILY;COUNT=50
+SUMMARY:1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+ 1234567890123456789012345678901234567890
+END:VEVENT
+END:VCALENDAR
+&quot;&quot;&quot;
+
+        calendar = yield self.calendarUnderTest(name=&quot;calendar&quot;, home=&quot;user01&quot;)
+        component = Component.fromString(data_floating % self.subs)
+        yield calendar.createCalendarObjectWithName(&quot;data2.ics&quot;, component)
+        yield self.commit()
+
+        # DTSTART DATE/rid DATE-TIME floating
+        cobj = yield self.calendarObjectUnderTest(name=&quot;data2.ics&quot;, calendar_name=&quot;calendar&quot;, home=&quot;user01&quot;)
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText(&quot;%(nowFloating)s&quot; % self.subs)), InvalidSplit)
+
+        # DTSTART DATE/rid DATE-TIME UTC
+        yield self.failUnlessFailure(cobj.splitAt(DateTime.parseText(&quot;%(now)s&quot; % self.subs)), InvalidSplit)
+
+
+
</ins><span class="cx"> class TimeRangeUpdateOptimization(CommonCommonTests, unittest.TestCase):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     CalendarObject time range optimization tests.
</span></span></pre>
</div>
</div>

</body>
</html>