[CalendarServer-changes] [11226] PyCalendar/trunk/src/pycalendar

source_changes at macosforge.org source_changes at macosforge.org
Tue May 21 06:40:40 PDT 2013


Revision: 11226
          http://trac.calendarserver.org//changeset/11226
Author:   cdaboo at apple.com
Date:     2013-05-21 06:40:40 -0700 (Tue, 21 May 2013)
Log Message:
-----------
Fix week number handling in date class so that BYWEEKNO recurrence works.

Modified Paths:
--------------
    PyCalendar/trunk/src/pycalendar/datetime.py
    PyCalendar/trunk/src/pycalendar/recurrence.py
    PyCalendar/trunk/src/pycalendar/tests/test_datetime.py
    PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py

Modified: PyCalendar/trunk/src/pycalendar/datetime.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/datetime.py	2013-05-21 13:35:26 UTC (rev 11225)
+++ PyCalendar/trunk/src/pycalendar/datetime.py	2013-05-21 13:40:40 UTC (rev 11226)
@@ -412,37 +412,73 @@
 
 
     def setWeekNo(self, weekno):
-        # This is the iso 8601 week number definition
+        """
+        Set the current date to one with the same day of the week in the current year with the
+        specified week number. Note this might cause the year to shift backwards or forwards
+        if the date is at the boundary between two years.
 
-        # What day does the current year start on
+        @param weekno: the week number to set (currently must be positive)
+        @type weekno: C{int}
+        """
+
+        # Don't both if already correct
+        if self.getWeekNo() == weekno:
+            return
+
+        # What day does the current year start on, and diff that with the current day
         temp = PyCalendarDateTime(year=self.mYear, month=1, day=1)
         first_day = temp.getDayOfWeek()
+        current_day = self.getDayOfWeek()
 
-        # Calculate and set yearday for start of week
-        if (first_day == PyCalendarDateTime.SUNDAY) or (first_day == PyCalendarDateTime.MONDAY) or \
-            (first_day == PyCalendarDateTime.TUESDAY) or (first_day == PyCalendarDateTime.WEDNESDAY) or (first_day == PyCalendarDateTime.THURSDAY):
-            self.setYearDay((weekno - 1) * 7 - first_day)
-        elif (first_day == PyCalendarDateTime.FRIDAY) or (first_day == PyCalendarDateTime.SATURDAY):
-            self.setYearDay((weekno - 1) * 7 - first_day + 7)
+        # Calculate and set yearday for start of week. The first week is the one that contains at least
+        # four days (with week start defaulting to MONDAY), so that means the 1st of January would fall
+        # on MO, TU, WE, TH.
+        if first_day in (PyCalendarDateTime.MONDAY, PyCalendarDateTime.TUESDAY, PyCalendarDateTime.WEDNESDAY, PyCalendarDateTime.THURSDAY):
+            year_day = (weekno - 1) * 7 + current_day - first_day
+        else:
+            year_day = weekno * 7 + current_day - first_day
 
+        # It is possible we have a negative offset which means go back to the prior year as part of
+        # week #1 exists at the end of that year.
+        if year_day < 0:
+            self.offsetYear(-1)
+        else:
+            year_day += 1
+        self.setYearDay(year_day)
 
+
     def getWeekNo(self):
-        # This is the iso 8601 week number definition
+        """
+        Return the ISO week number for the current date.
+        """
 
         # What day does the current year start on
         temp = PyCalendarDateTime(year=self.mYear, month=1, day=1)
         first_day = temp.getDayOfWeek()
+        if first_day == 0:
+            first_day = 7
+        current_day = self.getDayOfWeek()
+        if current_day == 0:
+            current_day = 7
 
-        # Get days upto the current one
-        yearday = self.getYearDay()
+        # This arithmetic uses the ISO day of week (1-7) and the year day to get the week number
+        week_no = (self.getYearDay() - current_day + 10) / 7
 
-        if (first_day == PyCalendarDateTime.SUNDAY) or (first_day == PyCalendarDateTime.MONDAY) or \
-            (first_day == PyCalendarDateTime.TUESDAY) or (first_day == PyCalendarDateTime.WEDNESDAY) or (first_day == PyCalendarDateTime.THURSDAY):
-            return (yearday + first_day) / 7 + 1
-        elif (first_day == PyCalendarDateTime.FRIDAY) or (first_day == PyCalendarDateTime.SATURDAY):
-            return (yearday + first_day - 7) / 7 + 1
+        # Might need to adjust forward/backwards based on year boundaries
+        if week_no == 0:
+            # Last week of previous year
+            temp = PyCalendarDateTime(year=self.mYear - 1, month=12, day=31)
+            week_no = temp.getWeekNo()
+        elif week_no == 53:
+            # Might be first week of next year
+            temp = PyCalendarDateTime(year=self.mYear + 1, month=1, day=1)
+            first_day = temp.getDayOfWeek()
+            if first_day in (PyCalendarDateTime.MONDAY, PyCalendarDateTime.TUESDAY, PyCalendarDateTime.WEDNESDAY, PyCalendarDateTime.THURSDAY):
+                week_no = 1
 
+        return week_no
 
+
     def isWeekNo(self, weekno):
         # This is the iso 8601 week number definition
 

Modified: PyCalendar/trunk/src/pycalendar/recurrence.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/recurrence.py	2013-05-21 13:35:26 UTC (rev 11225)
+++ PyCalendar/trunk/src/pycalendar/recurrence.py	2013-05-21 13:40:40 UTC (rev 11226)
@@ -884,7 +884,6 @@
                 float_until.offsetSeconds(float_offset)
 
         # Always add the initial instance DTSTART
-        items.append(start.duplicate())
         if self.mUseCount:
             # Bump counter and exit if over
             ctr += 1

Modified: PyCalendar/trunk/src/pycalendar/tests/test_datetime.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/tests/test_datetime.py	2013-05-21 13:35:26 UTC (rev 11225)
+++ PyCalendar/trunk/src/pycalendar/tests/test_datetime.py	2013-05-21 13:40:40 UTC (rev 11226)
@@ -322,3 +322,51 @@
         self.assertTrue(dt2.mPosixTimeCached)
         self.assertEqual(dt2.mPosixTime, dt.mPosixTime)
         self.assertEqual(dt2.mTZOffset, 0)
+
+
+    def testSetWeekNo(self):
+
+        dt = PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+        self.assertEqual(dt.getWeekNo(), 1)
+        dt.setWeekNo(1)
+        self.assertEqual(dt, PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 1)
+
+        dt = PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+        self.assertEqual(dt.getWeekNo(), 1)
+        dt.setWeekNo(2)
+        self.assertEqual(dt, PyCalendarDateTime(2013, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 2)
+
+        dt = PyCalendarDateTime(2013, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+        self.assertEqual(dt.getWeekNo(), 2)
+        dt.setWeekNo(1)
+        self.assertEqual(dt, PyCalendarDateTime(2013, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 1)
+
+        dt = PyCalendarDateTime(2014, 1, 7, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+        self.assertEqual(dt.getWeekNo(), 2)
+        dt.setWeekNo(1)
+        self.assertEqual(dt, PyCalendarDateTime(2013, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 1)
+
+        dt = PyCalendarDateTime(2012, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+        self.assertEqual(dt.getWeekNo(), 1)
+        dt.setWeekNo(1)
+        self.assertEqual(dt, PyCalendarDateTime(2012, 12, 31, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 1)
+
+        dt = PyCalendarDateTime(2016, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+        self.assertEqual(dt.getWeekNo(), 53)
+        dt.setWeekNo(1)
+        self.assertEqual(dt, PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 1)
+        dt.setWeekNo(2)
+        self.assertEqual(dt, PyCalendarDateTime(2016, 1, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 2)
+
+        dt = PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+        self.assertEqual(dt.getWeekNo(), 1)
+        dt.setWeekNo(1)
+        self.assertEqual(dt, PyCalendarDateTime(2016, 1, 8, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)))
+        self.assertEqual(dt.getWeekNo(), 1)

Modified: PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py
===================================================================
--- PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py	2013-05-21 13:35:26 UTC (rev 11225)
+++ PyCalendar/trunk/src/pycalendar/tests/test_recurrence.py	2013-05-21 13:40:40 UTC (rev 11226)
@@ -14,6 +14,8 @@
 #    limitations under the License.
 ##
 
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.period import PyCalendarPeriod
 from pycalendar.recurrence import PyCalendarRecurrence
 import unittest
 
@@ -111,3 +113,28 @@
         hashes.sort()
         for i in range(1, len(hashes)):
             self.assertNotEqual(hashes[i - 1], hashes[i])
+
+
+    def testByWeekNoExpand(self):
+
+        recur = PyCalendarRecurrence()
+        recur.parse("FREQ=YEARLY;BYWEEKNO=1,2")
+        start = PyCalendarDateTime(2013, 1, 1, 0, 0, 0)
+        end = PyCalendarDateTime(2017, 1, 1, 0, 0, 0)
+        items = []
+        range = PyCalendarPeriod(start, end)
+        recur.expand(start, range, items)
+        self.assertEqual(
+            items,
+            [
+                PyCalendarDateTime(2013, 1, 1, 0, 0, 0),
+                PyCalendarDateTime(2013, 1, 8, 0, 0, 0),
+                PyCalendarDateTime(2014, 1, 1, 0, 0, 0),
+                PyCalendarDateTime(2014, 1, 8, 0, 0, 0),
+                PyCalendarDateTime(2015, 1, 1, 0, 0, 0),
+                PyCalendarDateTime(2015, 1, 8, 0, 0, 0),
+                PyCalendarDateTime(2016, 1, 8, 0, 0, 0),
+                PyCalendarDateTime(2016, 1, 15, 0, 0, 0),
+            ],
+        )
+        print items
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130521/c3e42fed/attachment-0001.html>


More information about the calendarserver-changes mailing list