Code

more lenient date input and addition Interval input support (sf bug 677764)
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Wed, 19 Mar 2003 05:18:11 +0000 (05:18 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Wed, 19 Mar 2003 05:18:11 +0000 (05:18 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1609 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
roundup/date.py
test/test_dates.py

index 8a3ae62b25b9ccdaffc0bd128ef072b426623409..e91d50932f76a6742e9657f7355d0d40cf2750ba 100644 (file)
@@ -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:
index 2654a03b665040455d71453581a28866a915c083..165a883ed2aebe4f4c428e6acbf389bf62464e76 100644 (file)
@@ -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<y>\d\d\d\d)-)?(?P<m>\d\d?)?-(?P<d>\d\d?))? # [yyyy-]mm-dd
+            (((?P<y>\d\d\d\d)[/-])?(?P<m>\d\d?)?[/-](?P<d>\d\d?))? # [yyyy-]mm-dd
             (?P<n>\.)?                                     # .
             (((?P<H>\d?\d):(?P<M>\d\d))?(:(?P<S>\d\d))?)?  # hh:mm:ss
             (?P<o>.+)?                                     # 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 + 6m>
         >>> Interval('1:00')/2
         <Interval + 0:30>
+        >>> Interval('2003-03-18')
+        <Interval + [number of days between now and 2003-03-18]>
+        >>> Interval('-4d 2003-03-18')
+        <Interval + [number of days between now and 2003-03-14]>
 
     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<s>[-+])?         # + or -
             \s*((?P<y>\d+\s*)y)?    # year
             \s*((?P<m>\d+\s*)m)?    # month
             \s*((?P<w>\d+\s*)w)?    # week
             \s*((?P<d>\d+\s*)d)?    # day
             \s*(((?P<H>\d+):(?P<M>\d+))?(:(?P<S>\d+))?)?   # time
-            \s*''', re.VERBOSE), serialised_re=re.compile('''
+            \s*(?P<D>
+                 (\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<s>[+-])?1?(?P<y>([ ]{3}\d|\d{4}))(?P<m>\d{2})(?P<d>\d{2})
             (?P<H>\d{2})(?P<M>\d{2})(?P<S>\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:
index 44f3f1023d7384b973346ae27df2b2abba79704f..fcd1d1d656dcb121a9fd6a47df98c1cc6a9868b4 100644 (file)
@@ -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')