Skip to content

Commit 7cc013d

Browse files
author
Andrey Lebedev
committed
extended date syntax to make range searches even more useful
1 parent 0fa6222 commit 7cc013d

File tree

7 files changed

+68
-47
lines changed

7 files changed

+68
-47
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Feature:
6363
- HTML templating files now have a .html extension
6464
- Roundup templates are now distributed much more sanely, allowing for
6565
3rd-party templates.
66+
- extended date syntax to make range searches even more useful
6667

6768
Fixed:
6869
- applied unicode patch. All data is stored in utf-8. Incoming messages

doc/user_guide.txt

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
User Guide
33
==========
44

5-
:Version: $Revision: 1.20 $
5+
:Version: $Revision: 1.21 $
66

77
.. contents::
88

@@ -99,13 +99,13 @@ of dates in one of two formats:
9999

100100
1. English syntax::
101101

102-
[[From] <value>][ To <value>]
102+
[From <value>][To <value>]
103103

104104
Keywords "From" and "To" are case insensitive. Keyword "From" is optional.
105105

106106
2. "Geek" syntax::
107107

108-
[<value>][; <value>]
108+
[<value>];[<value>]
109109

110110
Either first or second ``<value>`` can be omitted in both syntaxes.
111111

@@ -117,24 +117,30 @@ active between period of time since 2 months up-till month ago.
117117

118118
Other possible examples (consider local time is Sat Mar 8 22:07:48 2003)::
119119

120-
>>> Range("from 2-12 to 4-2")
121-
<Range from 2003-02-12.00:00:00 to 2003-04-02.00:00:00>
122-
123-
>>> Range("18:00 TO +2m")
124-
<Range from 2003-03-08.18:00:00 to 2003-05-08.20:07:48>
125-
126-
>>> Range("12:00")
127-
<Range from 2003-03-08.12:00:00 to None>
128-
129-
>>> Range("tO +3d")
130-
<Range from None to 2003-03-11.20:07:48>
131-
132-
>>> Range("2002-11-10; 2002-12-12")
133-
<Range from 2002-11-10.00:00:00 to 2002-12-12.00:00:00>
134-
135-
>>> Range("; 20:00 +1d")
136-
<Range from None to 2003-03-09.20:00:00>
120+
>>> Range("from 2-12 to 4-2")
121+
<Range from 2003-02-12.00:00:00 to 2003-04-02.00:00:00>
122+
123+
>>> Range("FROM 18:00 TO +2m")
124+
<Range from 2003-03-08.18:00:00 to 2003-05-08.20:07:48>
125+
126+
>>> Range("12:00;")
127+
<Range from 2003-03-08.12:00:00 to None>
128+
129+
>>> Range("tO +3d")
130+
<Range from None to 2003-03-11.20:07:48>
131+
132+
>>> Range("2002-11-10; 2002-12-12")
133+
<Range from 2002-11-10.00:00:00 to 2002-12-12.00:00:00>
137134

135+
>>> Range("; 20:00 +1d")
136+
<Range from None to 2003-03-09.20:00:00>
137+
138+
>>> Range("2003")
139+
<Range from 2003-01-01.00:00:00 to 2003-12-31.23:59:59>
140+
141+
>>> Range("2003-04")
142+
<Range from 2003-04-01.00:00:00 to 2003-04-30.23:59:59>
143+
138144

139145
Interval properties
140146
~~~~~~~~~~~~~~~~~~~
@@ -486,10 +492,10 @@ The basic usage is::
486492
-u -- the user[:password] to use for commands
487493
-d -- print full designators not just class id numbers
488494
-c -- when outputting lists of data, comma-separate them.
489-
Same as '-S ","'.
495+
Same as '-S ","'.
490496
-S <string> -- when outputting lists of data, string-separate them
491497
-s -- when outputting lists of data, space-separate them.
492-
Same as '-S " "'.
498+
Same as '-S " "'.
493499

494500
Only one of -s, -c or -S can be specified.
495501

@@ -549,6 +555,8 @@ printed results:
549555
"11-07.09:32:43" yyyy-11-07.14:32:43
550556
"14:25" yyyy-mm-dd.19:25:00
551557
"8:47:11" yyyy-mm-dd.13:47:11
558+
"2003" 2003-01-01.00:00:00
559+
"2003-04" 2003-04-01.00:00:00
552560
"." "right now"
553561

554562
- Link values are printed as item designators. When given as an argument,
@@ -625,7 +633,7 @@ You can also display issue contents::
625633
or status::
626634

627635
shell% roundup-admin get name `/tools/roundup/bin/roundup-admin \
628-
-dc -i /var/roundup/sysadmin get status issue3,issue1`
636+
-dc -i /var/roundup/sysadmin get status issue3,issue1`
629637
unread
630638
deferred
631639

@@ -644,7 +652,7 @@ which is the same as::
644652
Also the tautological::
645653

646654
shell% roundup-admin get name \
647-
`roundup-admin -dc get status \`roundup-admin -dc find issue \
655+
`roundup-admin -dc get status \`roundup-admin -dc find issue \
648656
status=chatting\``
649657
chatting
650658
chatting

roundup/backends/back_anydbm.py

Lines changed: 3 additions & 3 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: back_anydbm.py,v 1.119 2003-04-20 11:58:45 kedder Exp $
18+
#$Id: back_anydbm.py,v 1.120 2003-04-22 20:53:54 kedder Exp $
1919
'''
2020
This module defines a backend that saves the hyperdatabase in a database
2121
chosen by anydbm. It is guaranteed to always be available in python
@@ -1767,10 +1767,10 @@ def filter(self, search_matches, filterspec, sort=(None,None),
17671767
elif t == DATE or t == INTERVAL:
17681768
if node[k] is None: break
17691769
if v.to_value:
1770-
if not (v.from_value < node[k] and v.to_value > node[k]):
1770+
if not (v.from_value <= node[k] and v.to_value >= node[k]):
17711771
break
17721772
else:
1773-
if not (v.from_value < node[k]):
1773+
if not (v.from_value <= node[k]):
17741774
break
17751775
elif t == OTHER:
17761776
# straight value comparison for the other types

roundup/backends/rdbms_common.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.54 2003-04-20 11:58:45 kedder Exp $
1+
# $Id: rdbms_common.py,v 1.55 2003-04-22 20:53:54 kedder Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -1852,10 +1852,10 @@ def filter(self, search_matches, filterspec, sort=(None,None),
18521852
# Try to filter on range of dates
18531853
date_rng = Range(v, date.Date, offset=timezone)
18541854
if (date_rng.from_value):
1855-
where.append('_%s > %s'%(k, a))
1855+
where.append('_%s >= %s'%(k, a))
18561856
args.append(date_rng.from_value.serialise())
18571857
if (date_rng.to_value):
1858-
where.append('_%s < %s'%(k, a))
1858+
where.append('_%s <= %s'%(k, a))
18591859
args.append(date_rng.to_value.serialise())
18601860
except ValueError:
18611861
# If range creation fails - ignore that search parameter
@@ -1870,10 +1870,10 @@ def filter(self, search_matches, filterspec, sort=(None,None),
18701870
# Try to filter on range of intervals
18711871
date_rng = Range(v, date.Interval)
18721872
if (date_rng.from_value):
1873-
where.append('_%s > %s'%(k, a))
1873+
where.append('_%s >= %s'%(k, a))
18741874
args.append(date_rng.from_value.serialise())
18751875
if (date_rng.to_value):
1876-
where.append('_%s < %s'%(k, a))
1876+
where.append('_%s <= %s'%(k, a))
18771877
args.append(date_rng.to_value.serialise())
18781878
except ValueError:
18791879
# If range creation fails - ignore that search parameter

roundup/date.py

Lines changed: 19 additions & 12 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.52 2003-04-21 14:29:39 kedder Exp $
18+
# $Id: date.py,v 1.53 2003-04-22 20:53:54 kedder Exp $
1919

2020
__doc__ = """
2121
Date, time and time interval handling.
@@ -59,6 +59,8 @@ class Date:
5959
"11-07.09:32:43" means <Date yyyy-11-07.14:32:43>
6060
"14:25" means <Date yyyy-mm-dd.19:25:00>
6161
"8:47:11" means <Date yyyy-mm-dd.13:47:11>
62+
"2003" means <Date 2003-01-01.00:00:00>
63+
"2003-06" means <Date 2003-06-01.00:00:00>
6264
"." means "right now"
6365
6466
The Date class should understand simple date expressions of the form
@@ -89,6 +91,7 @@ class Date:
8991
minute, second) is the serialisation format returned by the serialise()
9092
method, and is accepted as an argument on instatiation.
9193
'''
94+
9295
def __init__(self, spec='.', offset=0, add_granularity=0):
9396
"""Construct a date given a specification and a time zone offset.
9497
@@ -104,8 +107,10 @@ def __init__(self, spec='.', offset=0, add_granularity=0):
104107
self.year, self.month, self.day, self.hour, self.minute, \
105108
self.second, x, x, x = time.gmtime(ts)
106109

110+
usagespec='[yyyy]-[mm]-[dd].[H]H:MM[:SS][offset]'
107111
def set(self, spec, offset=0, date_re=re.compile(r'''
108-
(((?P<y>\d\d\d\d)[/-])?(?P<m>\d\d?)?[/-](?P<d>\d\d?))? # [yyyy-]mm-dd
112+
((?P<y>\d\d\d\d)([/-](?P<m>\d\d?)([/-](?P<d>\d\d?))?)? # yyyy[-mm[-dd]]
113+
|(?P<a>\d\d?)[/-](?P<b>\d\d?))? # or mm-dd
109114
(?P<n>\.)? # .
110115
(((?P<H>\d?\d):(?P<M>\d\d))?(:(?P<S>\d\d))?)? # hh:mm:ss
111116
(?P<o>.+)? # offset
@@ -125,24 +130,27 @@ def set(self, spec, offset=0, date_re=re.compile(r'''
125130
# not serialised data, try usual format
126131
m = date_re.match(spec)
127132
if m is None:
128-
raise ValueError, _('Not a date spec: [[yyyy-]mm-dd].'
129-
'[[h]h:mm[:ss]][offset]')
133+
raise ValueError, _('Not a date spec: %s' % self.usagespec)
130134

131135
info = m.groupdict()
132136

133137
if add_granularity:
134-
_add_granularity(info, 'SMHdmy')
138+
_add_granularity(info, 'SMHdmyab')
135139

136140
# get the current date as our default
137141
y,m,d,H,M,S,x,x,x = time.gmtime(time.time())
138142

139-
# override year, month, day parts
140-
if info['m'] is not None and info['d'] is not None:
141-
m = int(info['m'])
142-
d = int(info['d'])
143+
if info['y'] is not None or info['a'] is not None:
143144
if info['y'] is not None:
144145
y = int(info['y'])
145-
# time defaults to 00:00:00 GMT - offset (local midnight)
146+
m,d = (1,1)
147+
if info['m'] is not None:
148+
m = int(info['m'])
149+
if info['d'] is not None:
150+
d = int(info['d'])
151+
if info['a'] is not None:
152+
m = int(info['a'])
153+
d = int(info['b'])
146154
H = -offset
147155
M = S = 0
148156

@@ -165,8 +173,7 @@ def set(self, spec, offset=0, date_re=re.compile(r'''
165173
try:
166174
self.applyInterval(Interval(info['o'], allowdate=0))
167175
except ValueError:
168-
raise ValueError, _('Not a date spec: [[yyyy-]mm-dd].'
169-
'[[h]h:mm[:ss]][offset]')
176+
raise ValueError, _('Not a date spec: %s' % self.usagespec)
170177

171178
def addInterval(self, interval):
172179
''' Add the interval to this date, returning the date tuple

test/test_dates.py

Lines changed: 5 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.23 2003-04-21 14:29:40 kedder Exp $
18+
# $Id: test_dates.py,v 1.24 2003-04-22 20:53:54 kedder Exp $
1919

2020
import unittest, time
2121

@@ -56,6 +56,8 @@ def testDate(self):
5656
ae(str(date), '%s-%02d-%02d.14:25:00'%(y, m, d))
5757
date = Date("8:47:11")
5858
ae(str(date), '%s-%02d-%02d.08:47:11'%(y, m, d))
59+
ae(str(Date('2003')), '2003-01-01.00:00:00')
60+
ae(str(Date('2004-06')), '2004-06-01.00:00:00')
5961

6062
def testDateError(self):
6163
self.assertRaises(ValueError, Date, "12")
@@ -249,6 +251,8 @@ def testGranularity(self):
249251
ae = self.assertEqual
250252
ae(str(Date('2003-2-12', add_granularity=1)), '2003-02-12.23:59:59')
251253
ae(str(Date('2003-1-1.23:00', add_granularity=1)), '2003-01-01.23:00:59')
254+
ae(str(Date('2003', add_granularity=1)), '2003-12-31.23:59:59')
255+
ae(str(Date('2003-5', add_granularity=1)), '2003-05-31.23:59:59')
252256
ae(str(Interval('+1w', add_granularity=1)), '+ 14d')
253257
ae(str(Interval('-2m 3w', add_granularity=1)), '- 2m 14d')
254258

test/test_db.py

Lines changed: 3 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.87 2003-04-21 22:38:48 richard Exp $
18+
# $Id: test_db.py,v 1.88 2003-04-22 20:53:55 kedder Exp $
1919

2020
import unittest, os, shutil, time
2121

@@ -703,6 +703,7 @@ def testFilteringRange(self):
703703
ae(filt(None, {'deadline': 'from 2003-02-16'}), ['2', '3', '4'])
704704
ae(filt(None, {'deadline': '2003-02-16;'}), ['2', '3', '4'])
705705
# year and month granularity
706+
ae(filt(None, {'deadline': '2002'}), [])
706707
ae(filt(None, {'deadline': '2003'}), ['1', '2', '3'])
707708
ae(filt(None, {'deadline': '2004'}), ['4'])
708709
ae(filt(None, {'deadline': '2003-02'}), ['2', '3'])
@@ -713,7 +714,7 @@ def testFilteringRange(self):
713714
ae(filt(None, {'foo': 'from 0:50 to 2:00'}), ['1'])
714715
ae(filt(None, {'foo': 'from 0:50 to 1d 2:00'}), ['1', '2'])
715716
ae(filt(None, {'foo': 'from 5:50'}), ['2'])
716-
ae(filt(None, {'foo': 'to 0:50'}), [])
717+
ae(filt(None, {'foo': 'to 0:05'}), [])
717718

718719
def testFilteringIntervalSort(self):
719720
ae, filt = self.filteringSetup()

0 commit comments

Comments
 (0)