Allow to use relative dates in the format (now|today)[+-][0-9](day|week|month|year)(s)? (Closes #137)

Also fix DateRange not accepting ranges of one day.
This commit is contained in:
Jaime Marquínez Ferrándiz 2013-04-28 11:39:37 +02:00
parent a11ea50319
commit 37254abc36
2 changed files with 28 additions and 5 deletions

View File

@ -105,7 +105,7 @@ def test_daterange(self):
self.assertTrue("19690721" in _ac) self.assertTrue("19690721" in _ac)
_firstmilenium = DateRange(end="10000101") _firstmilenium = DateRange(end="10000101")
self.assertTrue("07110427" in _firstmilenium) self.assertTrue("07110427" in _firstmilenium)
def test_unified_dates(self): def test_unified_dates(self):
self.assertEqual(unified_strdate('December 21, 2010'), '20101221') self.assertEqual(unified_strdate('December 21, 2010'), '20101221')
self.assertEqual(unified_strdate('8/7/2009'), '20090708') self.assertEqual(unified_strdate('8/7/2009'), '20090708')

View File

@ -586,7 +586,29 @@ def unified_strdate(date_str):
return upload_date return upload_date
def date_from_str(date_str): def date_from_str(date_str):
"""Return a datetime object from a string in the format YYYYMMDD""" """
Return a datetime object from a string in the format YYYYMMDD or
(now|today)[+-][0-9](day|week|month|year)(s)?"""
today = datetime.date.today()
if date_str == 'now'or date_str == 'today':
return today
match = re.match('(now|today)(?P<sign>[+-])(?P<time>\d+)(?P<unit>day|week|month|year)(s)?', date_str)
if match is not None:
sign = match.group('sign')
time = int(match.group('time'))
if sign == '-':
time = -time
unit = match.group('unit')
#A bad aproximation?
if unit == 'month':
unit = 'day'
time *= 30
elif unit == 'year':
unit = 'day'
time *= 365
unit += 's'
delta = datetime.timedelta(**{unit: time})
return today + delta
return datetime.datetime.strptime(date_str, "%Y%m%d").date() return datetime.datetime.strptime(date_str, "%Y%m%d").date()
class DateRange(object): class DateRange(object):
@ -601,7 +623,7 @@ def __init__(self, start=None, end=None):
self.end = date_from_str(end) self.end = date_from_str(end)
else: else:
self.end = datetime.datetime.max.date() self.end = datetime.datetime.max.date()
if self.start >= self.end: if self.start > self.end:
raise ValueError('Date range: "%s" , the start date must be before the end date' % self) raise ValueError('Date range: "%s" , the start date must be before the end date' % self)
@classmethod @classmethod
def day(cls, day): def day(cls, day):
@ -609,7 +631,8 @@ def day(cls, day):
return cls(day,day) return cls(day,day)
def __contains__(self, date): def __contains__(self, date):
"""Check if the date is in the range""" """Check if the date is in the range"""
date = date_from_str(date) if not isinstance(date, datetime.date):
return self.start <= date and date <= self.end date = date_from_str(date)
return self.start <= date <= self.end
def __str__(self): def __str__(self):
return '%s - %s' % ( self.start.isoformat(), self.end.isoformat()) return '%s - %s' % ( self.start.isoformat(), self.end.isoformat())