date: fix matching of underspecified date ranges
In a date like 10:30, there are two underspecified ends: the specific
end (seconds) and the broad end (day, month, year). When matching
"10:30", we need to allow the specific end to go from 0 to 59 seconds,
while the broad end is assumed to be today's date.
Similar handling applies for a date range like "Mar 1": year is fixed
to today, any time matches.
--- a/mercurial/util.py Wed Dec 29 11:18:27 2010 -0600
+++ b/mercurial/util.py Wed Dec 29 14:04:47 2010 -0600
@@ -1079,11 +1079,16 @@
date = " ".join(string.split()[:-1])
# add missing elements from defaults
- for part in defaults:
+ usenow = False # default to using biased defaults
+ for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
found = [True for p in part if ("%"+p) in format]
if not found:
- date += "@" + defaults[part]
+ date += "@" + defaults[part][usenow]
format += "@%" + part[0]
+ else:
+ # We've found a specific time element, less specific time
+ # elements are relative to today
+ usenow = True
timetuple = time.strptime(date, format)
localunixtime = int(calendar.timegm(timetuple))
@@ -1095,8 +1100,8 @@
unixtime = localunixtime + offset
return unixtime, offset
-def parsedate(date, formats=None, defaults=None):
- """parse a localized date/time string and return a (unixtime, offset) tuple.
+def parsedate(date, formats=None, bias={}):
+ """parse a localized date/time and return a (unixtime, offset) tuple.
The date may be a "unixtime offset" string or in one of the specified
formats. If the date already is a (unixtime, offset) tuple, it is returned.
@@ -1112,15 +1117,22 @@
when, offset = map(int, date.split(' '))
except ValueError:
# fill out defaults
- if not defaults:
- defaults = {}
now = makedate()
+ defaults = {}
+ nowmap = {}
for part in ("d", "mb", "yY", "HI", "M", "S"):
- if part not in defaults:
+ # this piece is for rounding the specific end of unknowns
+ b = bias.get(part)
+ if b is None:
if part[0] in "HMS":
- defaults[part] = "00"
+ b = "00"
else:
- defaults[part] = datestr(now, "%" + part[0])
+ b = "0"
+
+ # this piece is for matching the generic end to today's date
+ n = datestr(now, "%" + part[0])
+
+ defaults[part] = (b, n)
for format in formats:
try:
@@ -1154,6 +1166,22 @@
'>{date}' on or after a given date
+ >>> p1 = parsedate("10:29:59")
+ >>> p2 = parsedate("10:30:00")
+ >>> p3 = parsedate("10:30:59")
+ >>> p4 = parsedate("10:31:00")
+ >>> p5 = parsedate("Sep 15 10:30:00 1999")
+ >>> f = matchdate("10:30")
+ >>> f(p1[0])
+ False
+ >>> f(p2[0])
+ True
+ >>> f(p3[0])
+ True
+ >>> f(p4[0])
+ False
+ >>> f(p5[0])
+ False
"""
def lower(date):
--- a/tests/test-doctest.py Wed Dec 29 11:18:27 2010 -0600
+++ b/tests/test-doctest.py Wed Dec 29 14:04:47 2010 -0600
@@ -16,6 +16,9 @@
import mercurial.url
doctest.testmod(mercurial.url)
+import mercurial.util
+doctest.testmod(mercurial.util)
+
import mercurial.encoding
doctest.testmod(mercurial.encoding)