lukkari/lukkari/daterange.py

69 lines
2.2 KiB
Python

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)
assert(end_obj - start_obj >= datetime.timedelta(0))
return Daterange(start_obj, end_obj - start_obj + datetime.timedelta(1))