# -*- coding: utf-8 -*- #Copyright 2013 Brandon Nielsen # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from duration import parse_duration from time import parse_datetime from date import parse_date def parse_interval(isointervalstr, intervaldelimiter='/', datetimedelimiter='T'): #Given a string representing an ISO8601 interval, return a #tuple of datetime.date or date.datetime objects representing the beginning #and end of the specified interval. Valid formats are: # #/ #/ #/ # #The and values can represent dates, or datetimes, #not times. # #The format: # # # #Is expressly not supported as there is no way to provide the addtional #required context. firstpart, secondpart = isointervalstr.split(intervaldelimiter) if firstpart[0] == 'P': #/ #Notice that these are not returned 'in order' (earlier to later), this #is to maintain consistency with parsing / durations, as #well asmaking repeating interval code cleaner. Users who desire #durations to be in order can use the 'sorted' operator. #We need to figure out if is a date, or a datetime if secondpart.find(datetimedelimiter) != -1: # is a datetime duration = parse_duration(firstpart) enddatetime = parse_datetime(secondpart, delimiter=datetimedelimiter) return (enddatetime, enddatetime - duration) else: # must just be a date duration = parse_duration(firstpart) enddate = parse_date(secondpart) return (enddate, enddate - duration) elif secondpart[0] == 'P': #/ #We need to figure out if is a date, or a datetime if firstpart.find(datetimedelimiter) != -1: # is a datetime duration = parse_duration(secondpart) startdatetime = parse_datetime(firstpart, delimiter=datetimedelimiter) return (startdatetime, startdatetime + duration) else: # must just be a date duration = parse_duration(secondpart) startdate = parse_date(firstpart) return (startdate, startdate + duration) else: #/ if firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) != -1: #Both parts are datetimes return (parse_datetime(firstpart, delimiter=datetimedelimiter), parse_datetime(secondpart, delimiter=datetimedelimiter)) elif firstpart.find(datetimedelimiter) != -1 and secondpart.find(datetimedelimiter) == -1: #First part is a datetime, second part is a date return (parse_datetime(firstpart, delimiter=datetimedelimiter), parse_date(secondpart)) elif firstpart.find(datetimedelimiter) == -1 and secondpart.find(datetimedelimiter) != -1: #First part is a date, second part is a datetime return (parse_date(firstpart), parse_datetime(secondpart, delimiter=datetimedelimiter)) else: #Both parts are dates return (parse_date(firstpart), parse_date(secondpart)) def parse_repeating_interval(isointervalstr, intervaldelimiter='/', datetimedelimiter='T'): #Given a string representing an ISO8601 interval repating, return a #generator of datetime.date or date.datetime objects representing the #dates specified by the repeating interval. Valid formats are: # #Rnn/ #R/ if isointervalstr[0] != 'R': raise ValueError('String is not a valid ISO8601 repeating interval.') #Parse the number of iterations iterationpart, intervalpart = isointervalstr.split(intervaldelimiter, 1) if len(iterationpart) > 1: iterations = int(iterationpart[1:]) else: iterations = None interval = parse_interval(intervalpart, intervaldelimiter, datetimedelimiter) intervaltimedelta = interval[1] - interval[0] #Now, build and return the generator if iterations != None: return date_generator(interval[0], intervaltimedelta, iterations) else: return date_generator_unbounded(interval[0], intervaltimedelta) def date_generator(startdate, timedelta, iterations): currentdate = startdate currentiteration = 0 while currentiteration < iterations: yield currentdate #Update the values currentdate += timedelta currentiteration += 1 def date_generator_unbounded(startdate, timedelta): currentdate = startdate while True: yield currentdate #Update the value currentdate += timedelta