def __init__(self, parent=None): super(VAlarm, self).__init__(parent=parent) self.mAction = definitions.eAction_VAlarm_Display self.mTriggerAbsolute = False self.mTriggerOnStart = True self.mTriggerOn = DateTime() # Set duration default to 1 hour self.mTriggerBy = Duration() self.mTriggerBy.setDuration(60 * 60) # Does not repeat by default self.mRepeats = 0 self.mRepeatInterval = Duration() self.mRepeatInterval.setDuration(5 * 60) # Five minutes # Status self.mStatusInit = False self.mAlarmStatus = definitions.eAlarm_Status_Pending self.mLastTrigger = DateTime() self.mNextTrigger = DateTime() self.mDoneCount = 0 # Create action data self.mActionData = VAlarm.VAlarmDisplay("")
def test_purgeOldEvents(self): # Dry run total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, None, DateTime(now, 4, 1, 0, 0, 0), 2, dryrun=True, debug=True )) self.assertEquals(total, 13) # Actually remove total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, None, DateTime(now, 4, 1, 0, 0, 0), 2, debug=True )) self.assertEquals(total, 13) # There should be no more left total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, None, DateTime(now, 4, 1, 0, 0, 0), 2, debug=True )) self.assertEquals(total, 0)
def parseSQLTimestampToPyCalendar(ts, withTimezone=None): """ Parse an SQL formated timestamp into a DateTime @param ts: the SQL timestamp @type ts: C{str} @return: L{DateTime} result """ if isinstance(ts, datetime): return DateTime( year=ts.year, month=ts.month, day=ts.day, hours=ts.hour, minutes=ts.minute, seconds=ts.second, tzid=withTimezone, ) else: # Format is "%Y-%m-%d %H:%M:%S" return DateTime( year=int(ts[0:4]), month=int(ts[5:7]), day=int(ts[8:10]), hours=int(ts[11:13]), minutes=int(ts[14:16]), seconds=int(ts[17:19]), tzid=withTimezone, )
def _addAvailabilityComponent(self, component, lowerLimit, upperLimit): """ Add the specified master VAVAILABILITY Component to the instance list, expanding it within the supplied time range. VAVAILABILITY components are not recurring, they have an optional DTSTART and DTEND/DURATION defining a single time-range which may be bounded depending on the presence of the properties. If unbounded at one or both ends, we will set the time to 1/1/1900 in the past and 1/1/3000 in the future. @param component: the Component to expand @param limit: the end L{DateTime} for expansion """ start = component.getStartDateUTC() if start: lowerLimit, upperLimit = self._setupLimits(start, lowerLimit, upperLimit) if start is not None and start >= upperLimit: # If the availability is beyond the end of the range we want, ignore it return if start is None: start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) start = self.normalizeFunction(start) end = component.getEndDateUTC() if lowerLimit is not None and end is not None and end < lowerLimit: # If the availability is before the start of the range we want, ignore it return if end is None: end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) end = self.normalizeFunction(end) self.addInstance(Instance(component, start, end))
def getVToDos(self, only_due, all_dates, upto_due_date, list): # Get current date-time less one day to test for completed events during the last day minusoneday = DateTime() minusoneday.setNowUTC() minusoneday.offsetDay(-1) today = DateTime() today.setToday() # Look at each VToDo for vtodo in self.getComponents(definitions.cICalComponent_VTODO): # Filter out done (that were complted more than a day ago) or cancelled to dos if required if only_due: if vtodo.getStatus() == definitions.eStatus_VToDo_Cancelled: continue elif ( (vtodo.getStatus() == definitions.eStatus_VToDo_Completed) and (not vtodo.hasCompleted() or (vtodo.getCompleted() < minusoneday)) ): continue # Filter out those with end after chosen date if required if not all_dates: if vtodo.hasEnd() and (vtodo.getEnd() > upto_due_date): continue elif not vtodo.hasEnd() and (today > upto_due_date): continue
def getUntilDate(self): if self._cached_until is None: year = 9999 month = 12 day = 1 hours = 0 minutes = 0 seconds = 0 mode = None if self.until and not self.until.startswith("#"): splits = self.until.split(" ") year = int(splits[0]) month = 1 day = 1 hours = 0 minutes = 0 seconds = 0 mode = None if len(splits) > 1 and not splits[1].startswith("#"): month = int(rule.Rule.MONTH_NAME_TO_POS[splits[1]]) if len(splits) > 2 and not splits[2].startswith("#"): if splits[2] == "lastSun": dt = DateTime(year=year, month=month, day=1) dt.setDayOfWeekInMonth(-1, DateTime.SUNDAY) splits[2] = dt.getDay() elif splits[2] == "lastSat": dt = DateTime(year=year, month=month, day=1) dt.setDayOfWeekInMonth(-1, DateTime.SATURDAY) splits[2] = dt.getDay() elif splits[2] == "Sun>=1": dt = DateTime(year=year, month=month, day=1) dt.setNextDayOfWeek(1, DateTime.SUNDAY) splits[2] = dt.getDay() elif splits[2] == "Sun>=8": dt = DateTime(year=year, month=month, day=1) dt.setNextDayOfWeek(8, DateTime.SUNDAY) splits[2] = dt.getDay() day = int(splits[2]) if len(splits) > 3 and not splits[3].startswith("#"): splits = splits[3].split(":") hours = int(splits[0]) minutes = int(splits[1][:2]) if len(splits[1]) > 2: mode = splits[1][2:] else: mode = None if len(splits) > 2: seconds = int(splits[2]) dt = DateTime(year=year, month=month, day=day, hours=hours, minutes=minutes, seconds=seconds) self._cached_until = utils.DateTime(dt, mode) return self._cached_until
def test_TimeFormattingAMPM(self): with translationTo('en', localeDir=localeDir) as t: self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 0, 0, 0)), "12:00 AM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 12, 0, 0)), "12:00 PM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 23, 59, 0)), "11:59 PM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 6, 5, 0)), "6:05 AM") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 16, 5, 0)), "4:05 PM")
def test_TimeFormatting24Hour(self): with translationTo('pig', localeDir=localeDir) as t: self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 0, 0, 0)), "00:00") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 12, 0, 0)), "12:00") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 23, 59, 0)), "23:59") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 6, 5, 0)), "06:05") self.assertEquals(t.dtTime(DateTime(2000, 1, 1, 16, 5, 0)), "16:05")
def __init__(self, parent=None): super(VFreeBusy, self).__init__(parent=parent) self.mStart = DateTime() self.mHasStart = False self.mEnd = DateTime() self.mHasEnd = False self.mDuration = False self.mCachedBusyTime = False self.mSpanPeriod = None self.mBusyTime = None
def testDuplicateInSet(self): s = set(( DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)), DateTime(2011, 1, 2, 0, 0, 0, tzid=Timezone(utc=True)), )) self.assertTrue( DateTime(2011, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)) in s) self.assertFalse( DateTime(2011, 1, 3, 0, 0, 0, tzid=Timezone(utc=True)) in s)
def test_parseSQLTimestampToPyCalendar(self): """ dateops.parseSQLTimestampToPyCalendar """ tests = ( ("2012-04-04 12:34:56", DateTime(2012, 4, 4, 12, 34, 56)), ("2012-12-31 01:01:01", DateTime(2012, 12, 31, 1, 1, 1)), ) for sqlStr, result in tests: self.assertEqual(parseSQLTimestampToPyCalendar(sqlStr), result)
def test_pyCalendarTodatetime(self): """ dateops.pyCalendarTodatetime """ tests = ( (DateTime(2012, 4, 4, 12, 34, 56), datetime.datetime(2012, 4, 4, 12, 34, 56, tzinfo=dateutil.tz.tzutc())), (DateTime(2012, 12, 31), datetime.date(2012, 12, 31)), ) for pycal, result in tests: self.assertEqual(pyCalendarTodatetime(pycal), result)
def test_truncatedDec(self): """ Custom VTZ valid from 2007. Daylight 2007 OK. """ TimezoneCache.create(empty=True) TimezoneCache.clear() self.doTest("TruncatedDec10.ics", DateTime(2007, 12, 10, 17, 0, 0, Timezone.UTCTimezone), DateTime(2007, 12, 10, 18, 0, 0, Timezone.UTCTimezone))
def test_pyCalendarToSQLTimestamp(self): """ dateops.pyCalendarToSQLTimestamp """ tests = ( (DateTime(2012, 4, 4, 12, 34, 56), datetime(2012, 4, 4, 12, 34, 56, tzinfo=None)), (DateTime(2012, 12, 31), date(2012, 12, 31)), ) for pycal, result in tests: self.assertEqual(pyCalendarToSQLTimestamp(pycal), result)
def test_parseSQLDateToPyCalendar(self): """ dateops.parseSQLDateToPyCalendar """ tests = ( ("2012-04-04", DateTime(2012, 4, 4)), ("2012-12-31 00:00:00", DateTime(2012, 12, 31)), ) for sqlStr, result in tests: self.assertEqual(parseSQLDateToPyCalendar(sqlStr), result)
def processAvailabilityFreeBusy(self, calendar, fbinfo): """ Extract free-busy data from a VAVAILABILITY component. @param calendar: the L{Component} that is the VCALENDAR containing the VAVAILABILITY's. @param fbinfo: the tuple used to store the three types of fb data. """ for vav in [ x for x in calendar.subcomponents() if x.name() == "VAVAILABILITY" ]: # Get overall start/end start = vav.getStartDateUTC() if start is None: start = DateTime(1900, 1, 1, 0, 0, 0, tzid=Timezone.UTCTimezone) end = vav.getEndDateUTC() if end is None: end = DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone.UTCTimezone) period = Period(start, end) overall = clipPeriod(period, self.timerange) if overall is None: continue # Now get periods for each instance of AVAILABLE sub-components periods = self.processAvailablePeriods(vav) # Now invert the periods and store in accumulator busyperiods = [] last_end = self.timerange.getStart() for period in periods: if last_end < period.getStart(): busyperiods.append(Period(last_end, period.getStart())) last_end = period.getEnd() if last_end < self.timerange.getEnd(): busyperiods.append(Period(last_end, self.timerange.getEnd())) # Add to actual results mapped by busy type fbtype = vav.propertyValue("BUSYTYPE") if fbtype is None: fbtype = "BUSY-UNAVAILABLE" getattr(fbinfo, self.FBInfo_mapper.get(fbtype, "unavailable")).extend(busyperiods)
def test_truncatedDecThenApr(self): """ Custom VTZ valid from 2007 loaded first. Daylight 2007 OK. """ TimezoneCache.create(empty=True) TimezoneCache.clear() self.doTest("TruncatedDec10.ics", DateTime(2007, 12, 10, 17, 0, 0, Timezone.UTCTimezone), DateTime(2007, 12, 10, 18, 0, 0, Timezone.UTCTimezone)) self.doTest("TruncatedApr01.ics", DateTime(2007, 04, 01, 16, 0, 0, Timezone.UTCTimezone), DateTime(2007, 04, 01, 17, 0, 0, Timezone.UTCTimezone))
def test_normalizeToUTC(self): """ Test that dateops.normalizeToUTC works correctly on all four types of date/time: date only, floating, UTC and local time. """ data = ( (DateTime(2012, 1, 1), DateTime(2012, 1, 1, 0, 0, 0, tzid=Timezone(utc=True))), (DateTime(2012, 1, 1, 10, 0, 0), DateTime(2012, 1, 1, 10, 0, 0, tzid=Timezone(utc=True))), (DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True)), DateTime(2012, 1, 1, 11, 0, 0, tzid=Timezone(utc=True))), (DateTime(2012, 1, 1, 12, 0, 0, tzid=Timezone(tzid="America/New_York")), DateTime(2012, 1, 1, 17, 0, 0, tzid=Timezone(utc=True))), ) for value, result in data: self.assertEqual(normalizeToUTC(value), result)
def test_datetimeforyear(self): data = ( ("Rule\tGuat\t2006\tonly\t-\tOct\t1\t0:00\t0\tS", 2006, DateTime(2006, 10, 1, 0, 0, 0), ""), ("Rule\tAlgeria\t1916\t1919\t-\tOct\tSun>=1\t23:00s\t0\t-", 1916, DateTime(1916, 10, 1, 23, 0, 0), "s"), ("Rule\tGhana\t1936\t1942\t-\tSep\t1\t0:00\t0:20\tGHST", 1937, DateTime(1937, 9, 1, 0, 0, 0), ""), ) for ruletext, year, dt, special in data: ruleitem = Rule() ruleitem.parse(ruletext) self.assertEqual(ruleitem.datetimeForYear(year), (dt, special))
def testSetUseDuration(self): p1 = Period( start=DateTime(2000, 1, 1, 0, 0, 0), end=DateTime(2000, 1, 1, 1, 0, 0), ) p1.setUseDuration(True) self.assertTrue(p1.getText(), "20000101T000000/PT1H") p2 = Period( start=DateTime(2000, 1, 1, 0, 0, 0), duration=Duration(hours=1), ) p2.setUseDuration(False) self.assertTrue(p2.getText(), "20000101T000000/20000101T010000")
def match(self, component, access=None): """ Returns True if the given calendar component matches this filter, False otherwise. """ # We only care about certain access restrictions. if access not in (Component.ACCESS_CONFIDENTIAL, Component.ACCESS_RESTRICTED): access = None # We need to prepare ourselves for a time-range query by pre-calculating # the set of instances up to the latest time-range limit. That way we can # avoid having to do some form of recurrence expansion for each query sub-part. maxend, isStartTime = self.getmaxtimerange() if maxend: if isStartTime: if component.isRecurringUnbounded(): # Unbounded recurrence is always within a start-only time-range instances = None else: # Expand the instances up to infinity instances = component.expandTimeRanges( DateTime(2100, 1, 1, 0, 0, 0, tzid=Timezone(utc=True)), ignoreInvalidInstances=True) else: instances = component.expandTimeRanges( maxend, ignoreInvalidInstances=True) else: instances = None self.child.setInstances(instances) # <filter> contains exactly one <comp-filter> return self.child.match(component, access)
def expandAll(self, start, end, with_name): if start is None: start = self.mStart # Ignore if there is no change in offset offsetto = self.loadValueInteger(definitions.cICalProperty_TZOFFSETTO, Value.VALUETYPE_UTC_OFFSET) offsetfrom = self.loadValueInteger(definitions.cICalProperty_TZOFFSETFROM, Value.VALUETYPE_UTC_OFFSET) # if offsetto == offsetfrom: # return () # Look for recurrences if self.mStart > end: # Return nothing return () elif not self.mRecurrences.hasRecurrence(): # Return DTSTART even if it is newer if self.mStart >= start: result = (self.mStart, offsetfrom, offsetto,) if with_name: result += (self.getTZName(),) return (result,) else: return () else: # We want to allow recurrence calculation caching to help us here # as this method # gets called a lot - most likely for ever increasing dt values # (which will therefore # invalidate the recurrence cache). # # What we will do is round up the date-time to the next year so # that the recurrence # cache is invalidated less frequently temp = DateTime(end.getYear(), 1, 1, 0, 0, 0) # Use cache of expansion if self.mCachedExpandBelowItems is None: self.mCachedExpandBelowItems = [] if self.mCachedExpandBelow is None: self.mCachedExpandBelow = self.mStart.duplicate() if temp > self.mCachedExpandBelow: self.mCachedExpandBelowItems = [] period = Period(self.mStart, end) self.mRecurrences.expand(self.mStart, period, self.mCachedExpandBelowItems, float_offset=self.mUTCOffsetFrom) self.mCachedExpandBelow = temp if len(self.mCachedExpandBelowItems) != 0: # Return them all within the range results = [] for dt in self.mCachedExpandBelowItems: if dt >= start and dt < end: result = (dt, offsetfrom, offsetto,) if with_name: result += (self.getTZName(),) results.append(result) return results return ()
def findTimezoneElement(self, dt): # Need to make the incoming date-time relative to the DTSTART in the # timezone component for proper comparison. # This means making the incoming date-time a floating (no timezone) # item temp = dt.duplicate() temp.setTimezoneID(None) # Had to rework this because some VTIMEZONEs have sub-components where the DST instances are interleaved. That # means we have to evaluate each and every sub-component to find the instance immediately less than the time we are checking. # Now do the expansion for each one found and pick the lowest found = None dt_found = DateTime() for item in self.mComponents: dt_item = item.expandBelow(temp) if temp >= dt_item: if found is not None: # Compare with the one previously cached and switch to this # one if newer if dt_item > dt_found: found = item dt_found = dt_item else: found = item dt_found = dt_item return found
def initNextTrigger(self): # Do not bother if its completed if self.mAlarmStatus == definitions.eAlarm_Status_Completed: return self.mStatusInit = True # Look for trigger immediately preceeding or equal to utc now nowutc = DateTime.getNowUTC() # Init done counter self.mDoneCount = 0 # Determine the first trigger trigger = DateTime() self.getFirstTrigger(trigger) while self.mDoneCount < self.mRepeats: # See if next trigger is later than now next_trigger = trigger + self.mRepeatInterval if next_trigger > nowutc: break self.mDoneCount += 1 trigger = next_trigger # Check for completion if trigger == self.mLastTrigger or ( nowutc - trigger).getTotalSeconds() > 24 * 60 * 60: if self.mDoneCount == self.mRepeats: self.mAlarmStatus = definitions.eAlarm_Status_Completed return else: trigger = trigger + self.mRepeatInterval self.mDoneCount += 1 self.mNextTrigger = trigger
def __init__(self, parent=None): super(VToDo, self).__init__(parent=parent) self.mPriority = 0 self.mStatus = definitions.eStatus_VToDo_None self.mPercentComplete = 0 self.mCompleted = DateTime() self.mHasCompleted = False
def test_eventsOlderThan(self): cutoff = DateTime(now, 4, 1, 0, 0, 0) txn = self._sqlCalendarStore.newTransaction() # Query for all old events results = (yield txn.eventsOlderThan(cutoff)) self.assertEquals( sorted(results), sorted([ ['home1', 'calendar1', 'old.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home1', 'calendar1', 'oldattachment1.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home1', 'calendar1', 'oldattachment2.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home1', 'calendar1', 'oldmattachment1.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home1', 'calendar1', 'oldmattachment2.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home2', 'calendar3', 'repeating_awhile.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home2', 'calendar2', 'recent.ics', parseSQLTimestamp('%s-03-04 22:15:00' % (now,))], ['home2', 'calendar2', 'oldattachment1.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home2', 'calendar2', 'oldattachment3.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home2', 'calendar2', 'oldattachment4.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home2', 'calendar2', 'oldmattachment1.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home2', 'calendar2', 'oldmattachment3.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ['home2', 'calendar2', 'oldmattachment4.ics', parseSQLTimestamp('1901-01-01 01:00:00')], ]) ) # Query for oldest event - actually with limited time caching, the oldest event # cannot be precisely known, all we get back is the first one in the sorted list # where each has the 1901 "dummy" time stamp to indicate a partial cache results = (yield txn.eventsOlderThan(cutoff, batchSize=1)) self.assertEquals(len(results), 1)
def datetimeForYear(self, year): """ Given a specific year, determine the actual date/time of the transition @param year: the year to determine the transition for @type year: C{int} @return: C{tuple} of L{DateTime} and C{str} (which is the special tzdata mode character """ # Create a floating date-time dt = DateTime() # Setup base year/month/day dt.setYear(year) dt.setMonth(Rule.MONTH_NAME_TO_POS[self.inMonth]) dt.setDay(1) # Setup base hours/minutes splits = self.atTime.split(":") if len(splits) == 1: splits.append("0") assert len(splits) == 2, "atTime format is wrong: %s, %s" % ( self.atTime, self, ) hours = int(splits[0]) if len(splits[1]) > 2: minutes = int(splits[1][:2]) special = splits[1][2:] else: minutes = int(splits[1]) special = "" # Special case for 24:00 if hours == 24 and minutes == 0: dt.setHours(23) dt.setMinutes(59) dt.setSeconds(59) else: dt.setHours(hours) dt.setMinutes(minutes) # Now determine the actual start day if self.onDay in Rule.LASTDAY_NAME_TO_DAY: dt.setDayOfWeekInMonth(-1, Rule.LASTDAY_NAME_TO_DAY[self.onDay]) elif self.onDay.find(">=") != -1: splits = self.onDay.split(">=") dt.setNextDayOfWeek(int(splits[1]), Rule.DAY_NAME_TO_DAY[splits[0]]) else: try: day = int(self.onDay) dt.setDay(day) except: assert False, "onDay value is not recognized: %s" % ( self.onDay, ) return dt, special
def test_truncatedAprThenDecFail(self): """ Custom VTZ with truncated standard time - 2006 loaded first. Daylight 2007 OK, standard 2007 wrong. """ TimezoneCache.create(empty=True) TimezoneCache.clear() self.doTest( "TruncatedApr01.ics", DateTime(2007, 04, 01, 16, 0, 0, Timezone.UTCTimezone), DateTime(2007, 04, 01, 17, 0, 0, Timezone.UTCTimezone), ) self.doTest("TruncatedDec10.ics", DateTime(2007, 12, 10, 17, 0, 0, Timezone.UTCTimezone), DateTime(2007, 12, 10, 18, 0, 0, Timezone.UTCTimezone), testEqual=False)
def test_truncatedAprThenDecOK(self): """ VTZ loaded from std timezone DB. 2007 OK. """ TimezoneCache.create() self.doTest( "TruncatedApr01.ics", DateTime(2007, 04, 01, 16, 0, 0, Timezone.UTCTimezone), DateTime(2007, 04, 01, 17, 0, 0, Timezone.UTCTimezone), ) self.doTest( "TruncatedDec10.ics", DateTime(2007, 12, 10, 17, 0, 0, Timezone.UTCTimezone), DateTime(2007, 12, 10, 18, 0, 0, Timezone.UTCTimezone), )
def test_purgeOldEvents_home_filtering(self): # Dry run total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, "ho", DateTime(now, 4, 1, 0, 0, 0), 2, dryrun=True, debug=True )) self.assertEquals(total, 13) # Dry run total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, "home", DateTime(now, 4, 1, 0, 0, 0), 2, dryrun=True, debug=True )) self.assertEquals(total, 13) # Dry run total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, "home1", DateTime(now, 4, 1, 0, 0, 0), 2, dryrun=True, debug=True )) self.assertEquals(total, 5) # Dry run total = (yield PurgeOldEventsService.purgeOldEvents( self._sqlCalendarStore, "home2", DateTime(now, 4, 1, 0, 0, 0), 2, dryrun=True, debug=True )) self.assertEquals(total, 8)