Skip to content

Commit 399e785

Browse files
author
Richard Jones
committed
Fix granularity stuff so it handles wrapping a lot better.
1 parent 58cb2fe commit 399e785

File tree

2 files changed

+41
-44
lines changed

2 files changed

+41
-44
lines changed

roundup/date.py

Lines changed: 36 additions & 33 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.93 2007-12-21 11:21:08 richard Exp $
18+
# $Id: date.py,v 1.94 2007-12-23 00:23:23 richard Exp $
1919

2020
"""Date, time and time interval handling.
2121
"""
@@ -33,20 +33,6 @@
3333

3434
from roundup import i18n
3535

36-
def _add_granularity(src, order, value=1):
37-
'''Increment first non-None value in src dictionary ordered by 'order'
38-
parameter
39-
'''
40-
for gran in order:
41-
if src[gran]:
42-
src[gran] = int(src[gran]) + value
43-
# XXX test and handle other cases
44-
if gran == 'm' and src['m'] > 12:
45-
y, m = divmod(src['m'], 12)
46-
src['m'] = m
47-
src['y'] = int(src['y']) + y
48-
break
49-
5036
# no, I don't know why we must anchor the date RE when we only ever use it
5137
# in a match()
5238
date_re = re.compile(r'''^
@@ -248,7 +234,8 @@ class Date:
248234
<Date 2003-07-01.00:00:0.000000>
249235
'''
250236

251-
def __init__(self, spec='.', offset=0, add_granularity=0, translator=i18n):
237+
def __init__(self, spec='.', offset=0, add_granularity=False,
238+
translator=i18n):
252239
"""Construct a date given a specification and a time zone offset.
253240
254241
'spec'
@@ -286,7 +273,7 @@ def __init__(self, spec='.', offset=0, add_granularity=0, translator=i18n):
286273
raise ValueError, 'Unknown spec %r' % (spec,)
287274

288275
def set(self, spec, offset=0, date_re=date_re,
289-
serialised_re=serialised_date_re, add_granularity=0):
276+
serialised_re=serialised_date_re, add_granularity=False):
290277
''' set the date to the value in spec
291278
'''
292279

@@ -308,8 +295,19 @@ def set(self, spec, offset=0, date_re=date_re,
308295

309296
info = m.groupdict()
310297

298+
# determine whether we need to add anything at the end
311299
if add_granularity:
312-
_add_granularity(info, 'SMHdmyab')
300+
for gran in 'SMHdmy':
301+
if info[gran] is not None:
302+
if gran == 'S':
303+
raise ValueError
304+
elif gran == 'M':
305+
add_granularity = Interval('00:01')
306+
elif gran == 'H':
307+
add_granularity = Interval('01:00')
308+
else:
309+
add_granularity = Interval('+1%s'%gran)
310+
break
313311

314312
# get the current date as our default
315313
dt = datetime.datetime.utcnow()
@@ -347,8 +345,6 @@ def set(self, spec, offset=0, date_re=date_re,
347345
# now handle the adjustment of hour
348346
frac = S - int(S)
349347
dt = datetime.datetime(y,m,d,H,M,int(S), int(frac * 1000000.))
350-
if add_granularity:
351-
dt = dt - datetime.timedelta(seconds=1)
352348
y, m, d, H, M, S, x, x, x = dt.timetuple()
353349
if adjust:
354350
y, m, d, H, M, S = _local_to_utc(y, m, d, H, M, S, offset)
@@ -365,6 +361,11 @@ def set(self, spec, offset=0, date_re=date_re,
365361
'"yyyy-mm-dd", "mm-dd", "HH:MM", "HH:MM:SS" or '
366362
'"yyyy-mm-dd.HH:MM:SS.SSS"')%(spec,)
367363

364+
# adjust by added granularity
365+
if add_granularity:
366+
self.applyInterval(add_granularity)
367+
self.applyInterval(Interval('- 00:00:01'))
368+
368369
def addInterval(self, interval):
369370
''' Add the interval to this date, returning the date tuple
370371
'''
@@ -616,7 +617,7 @@ class Interval:
616617
617618
TODO: more examples, showing the order of addition operation
618619
'''
619-
def __init__(self, spec, sign=1, allowdate=1, add_granularity=0,
620+
def __init__(self, spec, sign=1, allowdate=1, add_granularity=False,
620621
translator=i18n
621622
):
622623
"""Construct an interval given a specification."""
@@ -658,7 +659,7 @@ def set(self, spec, allowdate=1, interval_re=re.compile('''
658659
)?''', re.VERBOSE), serialised_re=re.compile('''
659660
(?P<s>[+-])?1?(?P<y>([ ]{3}\d|\d{4}))(?P<m>\d{2})(?P<d>\d{2})
660661
(?P<H>\d{2})(?P<M>\d{2})(?P<S>\d{2})''', re.VERBOSE),
661-
add_granularity=0):
662+
add_granularity=False):
662663
''' set the date to the value in spec
663664
'''
664665
self.year = self.month = self.week = self.day = self.hour = \
@@ -676,7 +677,10 @@ def set(self, spec, allowdate=1, interval_re=re.compile('''
676677
# pull out all the info specified
677678
info = m.groupdict()
678679
if add_granularity:
679-
_add_granularity(info, 'SMHdwmy', (info['s']=='-' and -1 or 1))
680+
for gran in 'SMHdwmy':
681+
if info[gran] is not None:
682+
info[gran] = int(info[gran]) + (info['s']=='-' and -1 or 1)
683+
break
680684

681685
valid = 0
682686
for group, attr in {'y':'year', 'm':'month', 'w':'week', 'd':'day',
@@ -1007,7 +1011,7 @@ class Range:
10071011
<Range from None to 2003-03-09.20:00:00>
10081012
10091013
"""
1010-
def __init__(self, spec, Type, allow_granularity=1, **params):
1014+
def __init__(self, spec, Type, allow_granularity=True, **params):
10111015
"""Initializes Range of type <Type> from given <spec> string.
10121016
10131017
Sets two properties - from_value and to_value. None assigned to any of
@@ -1016,28 +1020,27 @@ def __init__(self, spec, Type, allow_granularity=1, **params):
10161020
10171021
The Type parameter here should be class itself (e.g. Date), not a
10181022
class instance.
1019-
10201023
"""
10211024
self.range_type = Type
10221025
re_range = r'(?:^|from(.+?))(?:to(.+?)$|$)'
10231026
re_geek_range = r'(?:^|(.+?));(?:(.+?)$|$)'
10241027
# Check which syntax to use
1025-
if spec.find(';') == -1:
1026-
# Native english
1027-
mch_range = re.search(re_range, spec.strip(), re.IGNORECASE)
1028-
else:
1028+
if ';' in spec:
10291029
# Geek
1030-
mch_range = re.search(re_geek_range, spec.strip())
1031-
if mch_range:
1032-
self.from_value, self.to_value = mch_range.groups()
1030+
m = re.search(re_geek_range, spec.strip())
1031+
else:
1032+
# Native english
1033+
m = re.search(re_range, spec.strip(), re.IGNORECASE)
1034+
if m:
1035+
self.from_value, self.to_value = m.groups()
10331036
if self.from_value:
10341037
self.from_value = Type(self.from_value.strip(), **params)
10351038
if self.to_value:
10361039
self.to_value = Type(self.to_value.strip(), **params)
10371040
else:
10381041
if allow_granularity:
10391042
self.from_value = Type(spec, **params)
1040-
self.to_value = Type(spec, add_granularity=1, **params)
1043+
self.to_value = Type(spec, add_granularity=True, **params)
10411044
else:
10421045
raise ValueError, "Invalid range"
10431046

test/test_dates.py

Lines changed: 5 additions & 11 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_dates.py,v 1.43 2007-12-21 11:21:09 richard Exp $
18+
# $Id: test_dates.py,v 1.44 2007-12-23 00:23:23 richard Exp $
1919
from __future__ import nested_scopes
2020

2121
import unittest
@@ -24,19 +24,10 @@
2424
import calendar
2525

2626
from roundup.date import Date, Interval, Range, fixTimeOverflow, \
27-
get_timezone, _add_granularity
27+
get_timezone
2828

2929

3030
class DateTestCase(unittest.TestCase):
31-
def testAddGranularity(self):
32-
def d(m=None, d=None, H=None, M=None, S=None, value=1):
33-
d = dict(y='2006', m=m, d=d, H=H, M=M, S=S)
34-
_add_granularity(d, 'SMHdmy', value)
35-
return d
36-
ae = self.assertEqual
37-
ae(d(), dict(y=2007, m=None, d=None, H=None, M=None, S=None))
38-
ae(d(m='1'), dict(y='2006', m=2, d=None, H=None, M=None, S=None))
39-
ae(d(m='12'), dict(y=2007, m=1, d=None, H=None, M=None, S=None))
4031

4132
def testDateInterval(self):
4233
ae = self.assertEqual
@@ -371,6 +362,7 @@ def testGranularity(self):
371362
ae(str(Date('2003-1-1.23:00', add_granularity=1)), '2003-01-01.23:00:59')
372363
ae(str(Date('2003', add_granularity=1)), '2003-12-31.23:59:59')
373364
ae(str(Date('2003-5', add_granularity=1)), '2003-05-31.23:59:59')
365+
ae(str(Date('2003-12', add_granularity=1)), '2003-12-31.23:59:59')
374366
ae(str(Interval('+1w', add_granularity=1)), '+ 14d')
375367
ae(str(Interval('-2m 3w', add_granularity=1)), '- 2m 14d')
376368

@@ -479,7 +471,9 @@ def testTZ(self):
479471
date = Date(date, tz)
480472
ae(str(date), '2006-01-01.11:00:00')
481473

474+
482475
class RangeTestCase(unittest.TestCase):
476+
483477
def testRange(self):
484478
ae = self.assertEqual
485479
r = Range('2006', Date)

0 commit comments

Comments
 (0)