Code

add "ago" to intervals in the past (sf bug 679232)
[roundup.git] / roundup / date.py
index a016133ddc4c2e7b08a3387c06cd21b58a06b520..7073238f66424fa2a0db85c34117f806409640ce 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.30 2002-09-23 07:09:15 richard Exp $
+# $Id: date.py,v 1.41 2003-02-07 01:01:25 richard Exp $
 
 __doc__ = """
 Date, time and time interval handling.
@@ -206,20 +206,25 @@ class Date:
         return '%4d-%02d-%02d.%02d:%02d:%02d'%(self.year, self.month, self.day,
             self.hour, self.minute, self.second)
 
-    def pretty(self):
+    def pretty(self, format='%d %B %Y'):
         ''' print up the date date using a pretty format...
+
+            Note that if the day is zero, and the day appears first in the
+            format, then the day number will be removed from output.
         '''
-        str = time.strftime('%d %B %Y', (self.year, self.month,
-            self.day, self.hour, self.minute, self.second, 0, 0, 0))
-        if str[0] == '0': return ' ' + str[1:]
+        str = time.strftime(format, (self.year, self.month, self.day,
+            self.hour, self.minute, self.second, 0, 0, 0))
+        # handle zero day by removing it
+        if format.startswith('%d') and str[0] == '0':
+            return ' ' + str[1:]
         return str
 
     def set(self, spec, offset=0, date_re=re.compile(r'''
-            (((?P<y>\d{4}-)?((?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
-            ''', re.VERBOSE), serialised_re=re.compile('''
+            ''', re.VERBOSE), serialised_re=re.compile(r'''
             (\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)
             ''', re.VERBOSE)):
         ''' set the date to the value in spec
@@ -239,14 +244,16 @@ class Date:
 
         info = m.groupdict()
 
-        # get the current date/time using the offset
+        # get the current date as our default
         y,m,d,H,M,S,x,x,x = time.gmtime(time.time())
 
         # override year, month, day parts
         if info['m'] is not None and info['d'] is not None:
             m = int(info['m'])
             d = int(info['d'])
-            if info['y'] is not None: y = int(info['y'])
+            if info['y'] is not None:
+                y = int(info['y'])
+            # time defaults to 00:00:00 now
             H = M = S = 0
 
         # override hour, minute, second parts
@@ -268,11 +275,10 @@ class Date:
         return '<Date %s>'%self.__str__()
 
     def local(self, offset):
-        """Return this date as yyyy-mm-dd.hh:mm:ss in a local time zone."""
-        t = (self.year, self.month, self.day, self.hour + offset, self.minute,
-             self.second, 0, 0, 0)
-        self.year, self.month, self.day, self.hour, self.minute, \
-            self.second, x, x, x = time.gmtime(calendar.timegm(t))
+        """ Return this date as yyyy-mm-dd.hh:mm:ss in a local time zone.
+        """
+        return Date((self.year, self.month, self.day, self.hour + offset,
+            self.minute, self.second, 0, 0, 0))
 
     def get_tuple(self):
         return (self.year, self.month, self.day, self.hour, self.minute,
@@ -354,6 +360,22 @@ class Interval:
             l.append('%d:%02d'%(self.hour, self.minute))
         return ' '.join(l)
 
+    def __add__(self, other):
+        if isinstance(other, Date):
+            # the other is a Date - produce a Date
+            return Date(other.addInterval(self))
+        elif isinstance(other, Interval):
+            # add the other Interval to this one
+            a = self.get_tuple()
+            b = other.get_tuple()
+            if b[0] < 0:
+                i = Interval([x-y for x,y in zip(a[1:],b[1:])])
+            else:
+                i = Interval([x+y for x,y in zip(a[1:],b[1:])])
+            return i
+        # nope, no idea what to do with this other...
+        raise TypeError, "Can't add %r"%other
+
     def set(self, spec, interval_re=re.compile('''
             \s*(?P<s>[-+])?         # + or -
             \s*((?P<y>\d+\s*)y)?    # year
@@ -362,7 +384,7 @@ class Interval:
             \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('''
-            (?P<s>[+-])(?P<y>\d{4})(?P<m>\d{2})(?P<d>\d{2})
+            (?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
         '''
@@ -439,6 +461,8 @@ class Interval:
             s = _('1/2 an hour')
         else:
             s = _('%(number)s/4 hour')%{'number': int(self.minute/15)}
+        if self.sign < 0: 
+            s = s + _(' ago')
         return s
 
     def get_tuple(self):
@@ -446,7 +470,8 @@ class Interval:
             self.minute, self.second)
 
     def serialise(self):
-        return '%s%4d%02d%02d%02d%02d%02d'%(self.sign, self.year, self.month,
+        sign = self.sign > 0 and '+' or '-'
+        return '%s%04d%02d%02d%02d%02d%02d'%(sign, self.year, self.month,
             self.day, self.hour, self.minute, self.second)