From 302836038c21e07bee50eae9873be1ab7cc62e2f Mon Sep 17 00:00:00 2001 From: richard Date: Wed, 19 Mar 2003 05:18:11 +0000 Subject: [PATCH] more lenient date input and addition Interval input support (sf bug 677764) git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1609 57a73879-2fb5-44c3-a270-3262357dd7e2 --- CHANGES.txt | 1 + roundup/date.py | 39 ++++++++++++++++++++++++++++++--------- test/test_dates.py | 15 ++++++++++++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 8a3ae62..e91d509 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -50,6 +50,7 @@ Feature: chapter "Searching Page" for details) - role names made case insensitive - added ability to restore retired nodes +- more lenient date input and addition Interval input support (sf bug 677764) Fixed: diff --git a/roundup/date.py b/roundup/date.py index 2654a03..165a883 100644 --- a/roundup/date.py +++ b/roundup/date.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: date.py,v 1.49 2003-03-19 03:25:30 richard Exp $ +# $Id: date.py,v 1.50 2003-03-19 05:18:10 richard Exp $ __doc__ = """ Date, time and time interval handling. @@ -96,7 +96,7 @@ class Date: self.second, x, x, x = time.gmtime(ts) def set(self, spec, offset=0, date_re=re.compile(r''' - (((?P\d\d\d\d)-)?(?P\d\d?)?-(?P\d\d?))? # [yyyy-]mm-dd + (((?P\d\d\d\d)[/-])?(?P\d\d?)?[/-](?P\d\d?))? # [yyyy-]mm-dd (?P\.)? # . (((?P\d?\d):(?P\d\d))?(:(?P\d\d))?)? # hh:mm:ss (?P.+)? # offset @@ -147,7 +147,7 @@ class Date: if info.get('o', None): try: - self.applyInterval(Interval(info['o'])) + self.applyInterval(Interval(info['o'], allowdate=0)) except ValueError: raise ValueError, _('Not a date spec: [[yyyy-]mm-dd].' '[[h]h:mm[:ss]][offset]') @@ -321,6 +321,10 @@ class Interval: >>> Interval('1:00')/2 + >>> Interval('2003-03-18') + + >>> Interval('-4d 2003-03-18') + Interval arithmetic is handled in a couple of special ways, trying to cater for the most common cases. Fundamentally, Intervals which @@ -341,10 +345,10 @@ class Interval: TODO: more examples, showing the order of addition operation ''' - def __init__(self, spec, sign=1): + def __init__(self, spec, sign=1, allowdate=1): """Construct an interval given a specification.""" if type(spec) == type(''): - self.set(spec) + self.set(spec, allowdate) else: if len(spec) == 7: self.sign, self.year, self.month, self.day, self.hour, \ @@ -355,14 +359,18 @@ class Interval: self.year, self.month, self.day, self.hour, self.minute, \ self.second = spec - def set(self, spec, interval_re=re.compile(''' + def set(self, spec, allowdate=1, interval_re=re.compile(''' \s*(?P[-+])? # + or - \s*((?P\d+\s*)y)? # year \s*((?P\d+\s*)m)? # month \s*((?P\d+\s*)w)? # week \s*((?P\d+\s*)d)? # day \s*(((?P\d+):(?P\d+))?(:(?P\d+))?)? # time - \s*''', re.VERBOSE), serialised_re=re.compile(''' + \s*(?P + (\d\d\d\d[/-])?(\d\d?)?[/-](\d\d?)? # [yyyy-]mm-dd + \.? # . + (\d?\d:\d\d)?(:\d\d)? # hh:mm:ss + )?''', re.VERBOSE), serialised_re=re.compile(''' (?P[+-])?1?(?P([ ]{3}\d|\d{4}))(?P\d{2})(?P\d{2}) (?P\d{2})(?P\d{2})(?P\d{2})''', re.VERBOSE)): ''' set the date to the value in spec @@ -375,8 +383,9 @@ class Interval: m = interval_re.match(spec) if not m: raise ValueError, _('Not an interval spec: [+-] [#y] [#m] [#w] ' - '[#d] [[[H]H:MM]:SS]') + '[#d] [[[H]H:MM]:SS] [date spec]') + # pull out all the info specified info = m.groupdict() valid = 0 for group, attr in {'y':'year', 'm':'month', 'w':'week', 'd':'day', @@ -385,7 +394,8 @@ class Interval: valid = 1 setattr(self, attr, int(info[group])) - if not valid: + # make sure it's valid + if not valid and not info['D']: raise ValueError, _('Not an interval spec: [+-] [#y] [#m] [#w] ' '[#d] [[[H]H:MM]:SS]') @@ -395,6 +405,17 @@ class Interval: if info['s'] is not None: self.sign = {'+':1, '-':-1}[info['s']] + # use a date spec if one is given + if allowdate and info['D'] is not None: + now = Date('.') + date = Date(info['D']) + # if no time part was specified, nuke it in the "now" date + if not date.hour or date.minute or date.second: + now.hour = now.minute = now.second = 0 + if date != now: + y = now - (date + self) + self.__init__(y.get_tuple()) + def __cmp__(self, other): """Compare this interval to another interval.""" if other is None: diff --git a/test/test_dates.py b/test/test_dates.py index 44f3f10..fcd1d1d 100644 --- a/test/test_dates.py +++ b/test/test_dates.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: test_dates.py,v 1.21 2003-03-19 03:25:30 richard Exp $ +# $Id: test_dates.py,v 1.22 2003-03-19 05:18:11 richard Exp $ import unittest, time @@ -35,6 +35,8 @@ class DateTestCase(unittest.TestCase): ae = self.assertEqual date = Date("2000-04-17") ae(str(date), '2000-04-17.00:00:00') + date = Date("2000/04/17") + ae(str(date), '2000-04-17.00:00:00') date = Date("2000-4-7") ae(str(date), '2000-04-07.00:00:00') date = Date("2000-4-17") @@ -44,6 +46,8 @@ class DateTestCase(unittest.TestCase): ae(str(date), '%s-01-25.00:00:00'%y) date = Date("2000-04-17.03:45") ae(str(date), '2000-04-17.03:45:00') + date = Date("2000/04/17.03:45") + ae(str(date), '2000-04-17.03:45:00') date = Date("08-13.22:13") ae(str(date), '%s-08-13.22:13:00'%y) date = Date("11-07.09:32:43") @@ -162,6 +166,15 @@ class DateTestCase(unittest.TestCase): ae(str(Interval(' 14:00 ')), '+ 14:00') ae(str(Interval(' 0:04:33 ')), '+ 0:04:33') + def testIntervalInitDate(self): + ae = self.assertEqual + now = Date('.') + now.hour = now.minute = now.second = 0 + then = now + Interval('2d') + ae(str(Interval(str(then))), '+ 2d') + then = now - Interval('2d') + ae(str(Interval(str(then))), '- 2d') + def testIntervalAdd(self): ae = self.assertEqual ae(str(Interval('1y') + Interval('1y')), '+ 2y') -- 2.30.2