# - - - B i r d N o t e S e t . _ _ t i m e F i l t e r
def __timeFilter ( self, monthKey, startDate, endDate,
startSeason, endSeason ):
'''Does this month contain records of interest?
[ (monthKey is a month name as "YYYY-MM") and
(startDate is an inclusive starting date as a
datetime.date, or None for no starting cutoff) and
(endDate is an inclusive ending date as a
datetime.date or None for no ending cutoff) and
(startSeason is an inclusive starting month and day
as a datetime.date or None for no starting cutoff) and
(endSeason is an inclusive ending month and day
as a datetime.date or None for no ending cutoff) ->
if monthKey's month might contain records in
those date and day-of-year ranges ->
return True
else -> return False ]
'''
First we must set up two datetime.date
instances representing the limits of monthKey's month. Rather than have to worry
about the date of the last day of each month, we use a
half-open interval [firstOfThis, firstOfNext) where the interval includes the
first day of the month, but does not include the first
day of the following month (which is easier to compute).
#-- 1 --
# [ firstOfThis := a datetime.date instance representing
# the first day of monthKey's month
# firstOfNext := a datetime.date instance representing
# the first day of the month following monthKey ]
#--
# NB: Positions within a YYYY-MM string:
# 0 1 2 3 4 5 6 7
# Y Y Y Y - M M
#--
yyyy = int(monthKey[:4])
mm = int(monthKey[5:])
firstOfThis = datetime.date(yyyy, mm, 1)
if mm==12:
firstOfNext = datetime.date(yyyy+1, 1, 1)
else:
firstOfNext = datetime.date(yyyy, mm+1, 1)
The selection logic is straightforward. When one of the limit
values is None, there is no cutoff at that
limit. Where there is a cutoff, we can use the handy property
that the normal comparison operators work on datetime.date instances.
If startDate is on or after firstOfNext, monthKey is too
early.
If endDate is before firstOfThis, monthKey is too late.
#-- 2 --
if ( (startDate is not None) and
(startDate >= firstOfNext) ):
return False
#-- 3 --
if ( (endDate is not None) and
(endDate < firstOfThis) ):
return False
To test for the correct month without regard to the
year, we use the datetime.date.replace() method
to create copies of the supplied startSeason
and endSeason with the year changed to yyyy. Each copy is then compared to the half-open
interval [firstOfThis, firstOfNext) as above.
#-- 4 --
if startSeason is not None:
start = startSeason.replace ( yyyy )
if start >= firstOfNext:
return False
#-- 5 --
if endSeason is not None:
end = endSeason.replace ( yyyy )
if end < firstOfThis:
return False
#-- 6 --
return True