Skip to content

Commit 5d28ca2

Browse files
author
Andrey Lebedev
committed
granularity based ranges
1 parent acf690d commit 5d28ca2

File tree

3 files changed

+54
-18
lines changed

3 files changed

+54
-18
lines changed

roundup/date.py

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: date.py,v 1.51 2003-03-22 22:43:21 richard Exp $
18+
# $Id: date.py,v 1.52 2003-04-21 14:29:39 kedder Exp $
1919

2020
__doc__ = """
2121
Date, time and time interval handling.
@@ -24,6 +24,15 @@
2424
import time, re, calendar, types
2525
from i18n import _
2626

27+
def _add_granularity(src, order, value = 1):
28+
'''Increment first non-None value in src dictionary ordered by 'order'
29+
parameter
30+
'''
31+
for gran in order:
32+
if src[gran]:
33+
src[gran] = int(src[gran]) + value
34+
break
35+
2736
class Date:
2837
'''
2938
As strings, date-and-time stamps are specified with the date in
@@ -80,15 +89,15 @@ class Date:
8089
minute, second) is the serialisation format returned by the serialise()
8190
method, and is accepted as an argument on instatiation.
8291
'''
83-
def __init__(self, spec='.', offset=0):
92+
def __init__(self, spec='.', offset=0, add_granularity=0):
8493
"""Construct a date given a specification and a time zone offset.
8594
8695
'spec' is a full date or a partial form, with an optional
8796
added or subtracted interval. Or a date 9-tuple.
8897
'offset' is the local time zone offset from GMT in hours.
8998
"""
9099
if type(spec) == type(''):
91-
self.set(spec, offset=offset)
100+
self.set(spec, offset=offset, add_granularity=add_granularity)
92101
else:
93102
y,m,d,H,M,S,x,x,x = spec
94103
ts = calendar.timegm((y,m,d,H+offset,M,S,0,0,0))
@@ -102,9 +111,10 @@ def set(self, spec, offset=0, date_re=re.compile(r'''
102111
(?P<o>.+)? # offset
103112
''', re.VERBOSE), serialised_re=re.compile(r'''
104113
(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)
105-
''', re.VERBOSE)):
114+
''', re.VERBOSE), add_granularity=0):
106115
''' set the date to the value in spec
107116
'''
117+
108118
m = serialised_re.match(spec)
109119
if m is not None:
110120
# we're serialised - easy!
@@ -120,6 +130,9 @@ def set(self, spec, offset=0, date_re=re.compile(r'''
120130

121131
info = m.groupdict()
122132

133+
if add_granularity:
134+
_add_granularity(info, 'SMHdmy')
135+
123136
# get the current date as our default
124137
y,m,d,H,M,S,x,x,x = time.gmtime(time.time())
125138

@@ -140,6 +153,9 @@ def set(self, spec, offset=0, date_re=re.compile(r'''
140153
S = 0
141154
if info['S'] is not None: S = int(info['S'])
142155

156+
if add_granularity:
157+
S = S - 1
158+
143159
# now handle the adjustment of hour
144160
ts = calendar.timegm((y,m,d,H,M,S,0,0,0))
145161
self.year, self.month, self.day, self.hour, self.minute, \
@@ -345,10 +361,10 @@ class Interval:
345361
346362
TODO: more examples, showing the order of addition operation
347363
'''
348-
def __init__(self, spec, sign=1, allowdate=1):
364+
def __init__(self, spec, sign=1, allowdate=1, add_granularity=0):
349365
"""Construct an interval given a specification."""
350366
if type(spec) == type(''):
351-
self.set(spec, allowdate)
367+
self.set(spec, allowdate=allowdate, add_granularity=add_granularity)
352368
else:
353369
if len(spec) == 7:
354370
self.sign, self.year, self.month, self.day, self.hour, \
@@ -372,7 +388,8 @@ def set(self, spec, allowdate=1, interval_re=re.compile('''
372388
(\d?\d:\d\d)?(:\d\d)? # hh:mm:ss
373389
)?''', re.VERBOSE), serialised_re=re.compile('''
374390
(?P<s>[+-])?1?(?P<y>([ ]{3}\d|\d{4}))(?P<m>\d{2})(?P<d>\d{2})
375-
(?P<H>\d{2})(?P<M>\d{2})(?P<S>\d{2})''', re.VERBOSE)):
391+
(?P<H>\d{2})(?P<M>\d{2})(?P<S>\d{2})''', re.VERBOSE),
392+
add_granularity=0):
376393
''' set the date to the value in spec
377394
'''
378395
self.year = self.month = self.week = self.day = self.hour = \
@@ -389,6 +406,9 @@ def set(self, spec, allowdate=1, interval_re=re.compile('''
389406

390407
# pull out all the info specified
391408
info = m.groupdict()
409+
if add_granularity:
410+
_add_granularity(info, 'SMHdwmy', (info['s']=='-' and -1 or 1))
411+
392412
valid = 0
393413
for group, attr in {'y':'year', 'm':'month', 'w':'week', 'd':'day',
394414
'H':'hour', 'M':'minute', 'S':'second'}.items():
@@ -654,7 +674,7 @@ class Range:
654674
<Range from None to 2003-03-09.20:00:00>
655675
656676
"""
657-
def __init__(self, spec, Type, **params):
677+
def __init__(self, spec, Type, allow_granularity=1, **params):
658678
"""Initializes Range of type <Type> from given <spec> string.
659679
660680
Sets two properties - from_value and to_value. None assigned to any of
@@ -666,8 +686,8 @@ class instance.
666686
667687
"""
668688
self.range_type = Type
669-
re_range = r'(?:^|(?:from)?(.+?))(?:to(.+?)$|$)'
670-
re_geek_range = r'(?:^|(.+?))(?:;(.+?)$|$)'
689+
re_range = r'(?:^|from(.+?))(?:to(.+?)$|$)'
690+
re_geek_range = r'(?:^|(.+?));(?:(.+?)$|$)'
671691
# Check which syntax to use
672692
if spec.find(';') == -1:
673693
# Native english
@@ -682,7 +702,11 @@ class instance.
682702
if self.to_value:
683703
self.to_value = Type(self.to_value.strip(), **params)
684704
else:
685-
raise ValueError, "Invalid range"
705+
if allow_granularity:
706+
self.from_value = Type(spec, **params)
707+
self.to_value = Type(spec, add_granularity=1, **params)
708+
else:
709+
raise ValueError, "Invalid range"
686710

687711
def __str__(self):
688712
return "from %s to %s" % (self.from_value, self.to_value)
@@ -691,12 +715,17 @@ def __repr__(self):
691715
return "<Range %s>" % self.__str__()
692716

693717
def test_range():
694-
rspecs = ("from 2-12 to 4-2", "18:00 TO +2m", "12:00", "tO +3d",
695-
"2002-11-10; 2002-12-12", "; 20:00 +1d")
718+
rspecs = ("from 2-12 to 4-2", "from 18:00 TO +2m", "12:00;", "tO +3d",
719+
"2002-11-10; 2002-12-12", "; 20:00 +1d", '2002-10-12')
720+
rispecs = ('from -1w 2d 4:32 to 4d', '-2w 1d')
696721
for rspec in rspecs:
697722
print '>>> Range("%s")' % rspec
698723
print `Range(rspec, Date)`
699724
print
725+
for rspec in rispecs:
726+
print '>>> Range("%s")' % rspec
727+
print `Range(rspec, Interval)`
728+
print
700729

701730
def test():
702731
intervals = (" 3w 1 d 2:00", " + 2d", "3w")
@@ -705,7 +734,7 @@ def test():
705734
print `Interval(interval)`
706735

707736
dates = (".", "2000-06-25.19:34:02", ". + 2d", "1997-04-17", "01-25",
708-
"08-13.22:13", "14:25")
737+
"08-13.22:13", "14:25", '2002-12')
709738
for date in dates:
710739
print '>>> Date("%s")'%date
711740
print `Date(date)`
@@ -716,6 +745,6 @@ def test():
716745
print `Date(date) + Interval(interval)`
717746

718747
if __name__ == '__main__':
719-
test_range()
748+
test()
720749

721750
# vim: set filetype=python ts=4 sw=4 et si

test/test_dates.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: test_dates.py,v 1.22 2003-03-19 05:18:11 richard Exp $
18+
# $Id: test_dates.py,v 1.23 2003-04-21 14:29:40 kedder Exp $
1919

2020
import unittest, time
2121

@@ -245,6 +245,13 @@ def testSorting(self):
245245
l = [i1, i2, i3]; l.sort()
246246
ae(l, [i1, i3, i2])
247247

248+
def testGranularity(self):
249+
ae = self.assertEqual
250+
ae(str(Date('2003-2-12', add_granularity=1)), '2003-02-12.23:59:59')
251+
ae(str(Date('2003-1-1.23:00', add_granularity=1)), '2003-01-01.23:00:59')
252+
ae(str(Interval('+1w', add_granularity=1)), '+ 14d')
253+
ae(str(Interval('-2m 3w', add_granularity=1)), '- 2m 14d')
254+
248255
def suite():
249256
return unittest.makeSuite(DateTestCase, 'test')
250257

test/test_db.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: test_db.py,v 1.85 2003-04-20 11:58:45 kedder Exp $
18+
# $Id: test_db.py,v 1.86 2003-04-21 14:29:40 kedder Exp $
1919

2020
import unittest, os, shutil, time
2121

@@ -698,7 +698,7 @@ def testFilteringRange(self):
698698
# Lets assume people won't invent a time machine, otherwise this test
699699
# may fail :)
700700
ae(filt(None, {'deadline': 'from 2003-02-16'}), ['2', '3'])
701-
ae(filt(None, {'deadline': '2003-02-16'}), ['2', '3'])
701+
ae(filt(None, {'deadline': '2003-02-16;'}), ['2', '3'])
702702
# Interval ranges
703703
ae(filt(None, {'foo': 'from 0:50 to 2:00'}), ['1'])
704704
ae(filt(None, {'foo': 'from 0:50 to 1d 2:00'}), ['1', '2'])

0 commit comments

Comments
 (0)