Skip to content

Commit

Permalink
Added support for different interval lengths for daterange.from_date,…
Browse files Browse the repository at this point in the history
… such as weeks, months and years.
  • Loading branch information
runfalk committed Mar 7, 2017
1 parent 867f132 commit 42b1194
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 2 deletions.
58 changes: 58 additions & 0 deletions spans/tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,64 @@ def test_from_date(self):
with self.assertRaises(TypeError):
daterange.from_date(datetime(2000, 1, 1))

def test_from_date_week(self):
self.assertEqual(
daterange.from_date(date(2000, 1, 1), what="week"),
daterange(date(1999, 12, 27), date(2000, 1, 3)))
self.assertEqual(
daterange.from_date(date(2000, 1, 2), what="week"),
daterange(date(1999, 12, 27), date(2000, 1, 3)))
self.assertEqual(
daterange.from_date(date(2000, 1, 3), what="week"),
daterange(date(2000, 1, 3), date(2000, 1, 10)))

def test_from_date_american_week(self):
self.assertEqual(
daterange.from_date(date(2000, 1, 1), what="american_week"),
daterange(date(1999, 12, 26), date(2000, 1, 2)))
self.assertEqual(
daterange.from_date(date(2000, 1, 2), what="american_week"),
daterange(date(2000, 1, 2), date(2000, 1, 9)))
self.assertEqual(
daterange.from_date(date(2000, 1, 3), what="american_week"),
daterange(date(2000, 1, 2), date(2000, 1, 9)))

def test_from_date_month(self):
self.assertEqual(
daterange.from_date(date(2000, 1, 1), what="month"),
daterange(date(2000, 1, 1), date(2000, 1, 31), upper_inc=True))
self.assertEqual(
daterange.from_date(date(2000, 1, 31), what="month"),
daterange(date(2000, 1, 1), date(2000, 1, 31), upper_inc=True))
self.assertEqual(
daterange.from_date(date(2000, 2, 15), what="month"),
daterange(date(2000, 2, 1), date(2000, 2, 29), upper_inc=True))
self.assertEqual(
daterange.from_date(date(2001, 2, 15), what="month"),
daterange(date(2001, 2, 1), date(2001, 2, 28), upper_inc=True))

def test_from_date_quarter(self):
self.assertEqual(
daterange.from_date(date(2000, 1, 1), what="quarter"),
daterange(date(2000, 1, 1), date(2000, 3, 31), upper_inc=True))
self.assertEqual(
daterange.from_date(date(2000, 2, 15), what="quarter"),
daterange(date(2000, 1, 1), date(2000, 3, 31), upper_inc=True))
self.assertEqual(
daterange.from_date(date(2000, 3, 31), what="quarter"),
daterange(date(2000, 1, 1), date(2000, 3, 31), upper_inc=True))

def test_from_date_year(self):
self.assertEqual(
daterange.from_date(date(2000, 1, 1), what="year"),
daterange(date(2000, 1, 1), date(2001, 1, 1)))
self.assertEqual(
daterange.from_date(date(2000, 6, 1), what="year"),
daterange(date(2000, 1, 1), date(2001, 1, 1)))
self.assertEqual(
daterange.from_date(date(2000, 12, 31), what="year"),
daterange(date(2000, 1, 1), date(2001, 1, 1)))

def test_last(self):
span = daterange(date(2000, 1, 1), date(2000, 2, 1))
self.assertEqual(span.last, date(2000, 1, 31))
Expand Down
22 changes: 20 additions & 2 deletions spans/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,7 @@ def __init__(self, lower=None, upper=None, lower_inc=None, upper_inc=None):
super(daterange, self).__init__(lower, upper, lower_inc, upper_inc)

@classmethod
def from_date(cls, date):
def from_date(cls, date, what=None):
"""
Create a day long daterange from for the given date.
Expand All @@ -1005,7 +1005,25 @@ def from_date(cls, date):
:return: A new range that contains the given date.
"""

return cls(date, date, upper_inc=True)
# TODO: Add subclasses that support stepping between the intervals.
# Calling next for a week would result in the coming week
if what is None or what == "day":
return cls(date, date, upper_inc=True)
elif what == "week":
start = date - timedelta(date.weekday())
return cls(start, start + timedelta(7))
elif what == "american_week":
start = date - timedelta((date.weekday() + 1) % 7)
return cls(start, start + timedelta(7))
elif what == "month":
start = date.replace(day=1)
return cls(start, (start + timedelta(31)).replace(day=1))
elif what == "quarter":
start = date.replace(month=(date.month - 1) // 3 * 3 + 1, day=1)
return cls(start, (start + timedelta(93)).replace(day=1))
elif what == "year":
start = date.replace(month=1, day=1)
return cls(start, (start + timedelta(366)).replace(day=1))

def __len__(self):
"""
Expand Down

0 comments on commit 42b1194

Please sign in to comment.