From 71a07137833d02857a61352d4d92546237cf14f9 Mon Sep 17 00:00:00 2001 From: kedder Date: Mon, 21 Apr 2003 14:29:40 +0000 Subject: [PATCH] granularity based ranges git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1669 57a73879-2fb5-44c3-a270-3262357dd7e2 --- roundup/date.py | 59 ++++++++++++++++++++++++++++++++++------------ test/test_dates.py | 9 ++++++- test/test_db.py | 4 ++-- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/roundup/date.py b/roundup/date.py index a6430d7..95777a3 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.51 2003-03-22 22:43:21 richard Exp $ +# $Id: date.py,v 1.52 2003-04-21 14:29:39 kedder Exp $ __doc__ = """ Date, time and time interval handling. @@ -24,6 +24,15 @@ Date, time and time interval handling. import time, re, calendar, types from i18n import _ +def _add_granularity(src, order, value = 1): + '''Increment first non-None value in src dictionary ordered by 'order' + parameter + ''' + for gran in order: + if src[gran]: + src[gran] = int(src[gran]) + value + break + class Date: ''' As strings, date-and-time stamps are specified with the date in @@ -80,7 +89,7 @@ class Date: minute, second) is the serialisation format returned by the serialise() method, and is accepted as an argument on instatiation. ''' - def __init__(self, spec='.', offset=0): + def __init__(self, spec='.', offset=0, add_granularity=0): """Construct a date given a specification and a time zone offset. 'spec' is a full date or a partial form, with an optional @@ -88,7 +97,7 @@ class Date: 'offset' is the local time zone offset from GMT in hours. """ if type(spec) == type(''): - self.set(spec, offset=offset) + self.set(spec, offset=offset, add_granularity=add_granularity) else: y,m,d,H,M,S,x,x,x = spec ts = calendar.timegm((y,m,d,H+offset,M,S,0,0,0)) @@ -102,9 +111,10 @@ class Date: (?P.+)? # offset ''', re.VERBOSE), serialised_re=re.compile(r''' (\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d) - ''', re.VERBOSE)): + ''', re.VERBOSE), add_granularity=0): ''' set the date to the value in spec ''' + m = serialised_re.match(spec) if m is not None: # we're serialised - easy! @@ -120,6 +130,9 @@ class Date: info = m.groupdict() + if add_granularity: + _add_granularity(info, 'SMHdmy') + # get the current date as our default y,m,d,H,M,S,x,x,x = time.gmtime(time.time()) @@ -140,6 +153,9 @@ class Date: S = 0 if info['S'] is not None: S = int(info['S']) + if add_granularity: + S = S - 1 + # now handle the adjustment of hour ts = calendar.timegm((y,m,d,H,M,S,0,0,0)) self.year, self.month, self.day, self.hour, self.minute, \ @@ -345,10 +361,10 @@ class Interval: TODO: more examples, showing the order of addition operation ''' - def __init__(self, spec, sign=1, allowdate=1): + def __init__(self, spec, sign=1, allowdate=1, add_granularity=0): """Construct an interval given a specification.""" if type(spec) == type(''): - self.set(spec, allowdate) + self.set(spec, allowdate=allowdate, add_granularity=add_granularity) else: if len(spec) == 7: self.sign, self.year, self.month, self.day, self.hour, \ @@ -372,7 +388,8 @@ class Interval: (\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)): + (?P\d{2})(?P\d{2})(?P\d{2})''', re.VERBOSE), + add_granularity=0): ''' set the date to the value in spec ''' self.year = self.month = self.week = self.day = self.hour = \ @@ -389,6 +406,9 @@ class Interval: # pull out all the info specified info = m.groupdict() + if add_granularity: + _add_granularity(info, 'SMHdwmy', (info['s']=='-' and -1 or 1)) + valid = 0 for group, attr in {'y':'year', 'm':'month', 'w':'week', 'd':'day', 'H':'hour', 'M':'minute', 'S':'second'}.items(): @@ -654,7 +674,7 @@ class Range: """ - def __init__(self, spec, Type, **params): + def __init__(self, spec, Type, allow_granularity=1, **params): """Initializes Range of type from given string. Sets two properties - from_value and to_value. None assigned to any of @@ -666,8 +686,8 @@ class Range: """ self.range_type = Type - re_range = r'(?:^|(?:from)?(.+?))(?:to(.+?)$|$)' - re_geek_range = r'(?:^|(.+?))(?:;(.+?)$|$)' + re_range = r'(?:^|from(.+?))(?:to(.+?)$|$)' + re_geek_range = r'(?:^|(.+?));(?:(.+?)$|$)' # Check which syntax to use if spec.find(';') == -1: # Native english @@ -682,7 +702,11 @@ class Range: if self.to_value: self.to_value = Type(self.to_value.strip(), **params) else: - raise ValueError, "Invalid range" + if allow_granularity: + self.from_value = Type(spec, **params) + self.to_value = Type(spec, add_granularity=1, **params) + else: + raise ValueError, "Invalid range" def __str__(self): return "from %s to %s" % (self.from_value, self.to_value) @@ -691,12 +715,17 @@ class Range: return "" % self.__str__() def test_range(): - rspecs = ("from 2-12 to 4-2", "18:00 TO +2m", "12:00", "tO +3d", - "2002-11-10; 2002-12-12", "; 20:00 +1d") + rspecs = ("from 2-12 to 4-2", "from 18:00 TO +2m", "12:00;", "tO +3d", + "2002-11-10; 2002-12-12", "; 20:00 +1d", '2002-10-12') + rispecs = ('from -1w 2d 4:32 to 4d', '-2w 1d') for rspec in rspecs: print '>>> Range("%s")' % rspec print `Range(rspec, Date)` print + for rspec in rispecs: + print '>>> Range("%s")' % rspec + print `Range(rspec, Interval)` + print def test(): intervals = (" 3w 1 d 2:00", " + 2d", "3w") @@ -705,7 +734,7 @@ def test(): print `Interval(interval)` dates = (".", "2000-06-25.19:34:02", ". + 2d", "1997-04-17", "01-25", - "08-13.22:13", "14:25") + "08-13.22:13", "14:25", '2002-12') for date in dates: print '>>> Date("%s")'%date print `Date(date)` @@ -716,6 +745,6 @@ def test(): print `Date(date) + Interval(interval)` if __name__ == '__main__': - test_range() + test() # vim: set filetype=python ts=4 sw=4 et si diff --git a/test/test_dates.py b/test/test_dates.py index fcd1d1d..54a4857 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.22 2003-03-19 05:18:11 richard Exp $ +# $Id: test_dates.py,v 1.23 2003-04-21 14:29:40 kedder Exp $ import unittest, time @@ -245,6 +245,13 @@ class DateTestCase(unittest.TestCase): l = [i1, i2, i3]; l.sort() ae(l, [i1, i3, i2]) + def testGranularity(self): + ae = self.assertEqual + ae(str(Date('2003-2-12', add_granularity=1)), '2003-02-12.23:59:59') + ae(str(Date('2003-1-1.23:00', add_granularity=1)), '2003-01-01.23:00:59') + ae(str(Interval('+1w', add_granularity=1)), '+ 14d') + ae(str(Interval('-2m 3w', add_granularity=1)), '- 2m 14d') + def suite(): return unittest.makeSuite(DateTestCase, 'test') diff --git a/test/test_db.py b/test/test_db.py index 8d0a49e..08a3ea5 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: test_db.py,v 1.85 2003-04-20 11:58:45 kedder Exp $ +# $Id: test_db.py,v 1.86 2003-04-21 14:29:40 kedder Exp $ import unittest, os, shutil, time @@ -698,7 +698,7 @@ class anydbmDBTestCase(MyTestCase): # Lets assume people won't invent a time machine, otherwise this test # may fail :) ae(filt(None, {'deadline': 'from 2003-02-16'}), ['2', '3']) - ae(filt(None, {'deadline': '2003-02-16'}), ['2', '3']) + ae(filt(None, {'deadline': '2003-02-16;'}), ['2', '3']) # Interval ranges ae(filt(None, {'foo': 'from 0:50 to 2:00'}), ['1']) ae(filt(None, {'foo': 'from 0:50 to 1d 2:00'}), ['1', '2']) -- 2.30.2