2016-08-24 12:12:52 +00:00
|
|
|
import datetime
|
|
|
|
|
|
|
|
class Daterange:
|
|
|
|
def __init__(self, start, length):
|
|
|
|
self.start = start
|
|
|
|
self.length = length
|
|
|
|
|
|
|
|
def range(self):
|
|
|
|
end = self.start + self.length - datetime.timedelta(1)
|
|
|
|
return (self.start, end)
|
|
|
|
|
|
|
|
def __contains__(self, day):
|
|
|
|
delta = day - self.start
|
|
|
|
return datetime.timedelta(0) <= delta and delta < self.length
|
|
|
|
|
|
|
|
def overlaps(self, other):
|
|
|
|
if other.start < self.start:
|
|
|
|
return other.overlaps(self)
|
|
|
|
|
|
|
|
assert(self.start <= other.start)
|
|
|
|
return other.start < self.start + self.length
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return 'Daterange(%s, %s)' % (repr(self.start), repr(self.length))
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
start, end = map(str, self.range())
|
|
|
|
return '%s - %s' % (start, end)
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return self.start == other.start and self.length == other.length
|
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
return not self == other
|
|
|
|
|
|
|
|
def week(year, week):
|
|
|
|
# Ensure that week is correct for the given year
|
|
|
|
assert(1 <= week and week <= 53)
|
|
|
|
if week == 53:
|
|
|
|
assert(datetime.date(year, 12, 31).isocalendar()[1] == 53)
|
|
|
|
|
|
|
|
# First attempt, this will most likely be wrong
|
|
|
|
# Use 28 instead of probably better 30 so we don't have to special-case february
|
|
|
|
days_into_year = 1 + week * 7
|
|
|
|
guess = datetime.date(year + days_into_year // 365, days_into_year // 28 % 12 + 1, week * 7 % 28 + 1)
|
|
|
|
guess_year, guess_week, guess_weekday = guess.isocalendar()
|
|
|
|
|
|
|
|
while guess_year != year or guess_week != week or guess_weekday != 1:
|
|
|
|
year_delta = year - guess_year
|
|
|
|
week_delta = week - guess_week
|
|
|
|
weekday_delta = 1 - guess_weekday
|
|
|
|
|
|
|
|
# Year is not quite right, but by repeated application year_delta should become 0, after which it's correct
|
|
|
|
delta = datetime.timedelta(year_delta * 365 + week_delta * 7 + weekday_delta)
|
|
|
|
|
|
|
|
guess += delta
|
|
|
|
guess_year, guess_week, guess_weekday = guess.isocalendar()
|
|
|
|
|
|
|
|
return Daterange(guess, datetime.timedelta(7))
|
|
|
|
|
|
|
|
def between(start, end):
|
|
|
|
assert(len(start) == 3 and len(end) == 3)
|
|
|
|
start_year, start_month, start_day = start
|
|
|
|
end_year, end_month, end_day = end
|
|
|
|
start_obj = datetime.date(start_year, start_month, start_day)
|
|
|
|
end_obj = datetime.date(end_year, end_month, end_day)
|
2016-08-24 12:28:41 +00:00
|
|
|
assert(end_obj - start_obj >= datetime.timedelta(0))
|
2016-08-24 12:12:52 +00:00
|
|
|
return Daterange(start_obj, end_obj - start_obj + datetime.timedelta(1))
|