Mercurial > hg-stable
changeset 3812:bf6ab30559e6
Add date matching support
Add extended date formats (eg "Dec", "2006")
Add a couple missing basic date formats
Improve default date element scheme to parsedate
Add matchdate function to match a date spec
Add -e switch and range matching to debugdate
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Wed, 06 Dec 2006 15:11:44 -0600 |
parents | 6fa11a9d7cac |
children | fc5ba0ab7f45 |
files | mercurial/commands.py mercurial/util.py |
diffstat | 2 files changed, 90 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/commands.py Wed Dec 06 13:36:23 2006 -0600 +++ b/mercurial/commands.py Wed Dec 06 15:11:44 2006 -0600 @@ -788,11 +788,17 @@ except KeyError: raise util.Abort(_('invalid revision identifier %s') % rev) -def debugdate(ui, date): +def debugdate(ui, date, range=None, **opts): """parse and display a date""" - d = util.parsedate(date) + if opts["extended"]: + d = util.parsedate(date, util.extendeddateformats) + else: + d = util.parsedate(date) ui.write("internal: %s %s\n" % d) ui.write("standard: %s\n" % util.datestr(d)) + if range: + m = util.matchdate(range) + ui.write("match: %s\n" % m(d[0])) def debugindex(ui, file_): """dump the contents of an index file""" @@ -2483,7 +2489,9 @@ "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')), "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')), "debugstate": (debugstate, [], _('debugstate')), - "debugdate": (debugdate, [], _('debugdata DATE')), + "debugdate": (debugdate, + [('e','extended', None, _('try extended date formats'))], + _('debugdata [-e] DATE [RANGE]')), "debugdata": (debugdata, [], _('debugdata FILE REV')), "debugindex": (debugindex, [], _('debugindex FILE')), "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
--- a/mercurial/util.py Wed Dec 06 13:36:23 2006 -0600 +++ b/mercurial/util.py Wed Dec 06 15:11:44 2006 -0600 @@ -85,6 +85,8 @@ '%a %b %d %H:%M:%S %Y', '%a %b %d %I:%M:%S%p %Y', '%b %d %H:%M:%S %Y', + '%b %d %I:%M:%S%p %Y', + '%b %d %H:%M:%S', '%b %d %I:%M:%S%p', '%b %d %H:%M', '%b %d %I:%M%p', @@ -96,6 +98,13 @@ '%I:%M%p', ) +extendeddateformats = defaultdateformats + ( + "%Y", + "%Y-%m", + "%b", + "%b %Y", + ) + class SignalInterrupt(Exception): """Exception raised on SIGTERM and SIGHUP.""" @@ -1058,7 +1067,7 @@ s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60)) return s -def strdate(string, format='%a %b %d %H:%M:%S %Y'): +def strdate(string, format, defaults): """parse a localized time string and return a (unixtime, offset) tuple. if the string cannot be parsed, ValueError is raised.""" def timezone(string): @@ -1076,16 +1085,12 @@ if offset != None: date = " ".join(string.split()[:-1]) - # add missing elements - if '%y' not in format.lower(): - date += "@" + datestr(makedate(), "%Y", False) - format += "@%Y" - if '%m' not in format and '%b' not in format: - date += "@" + datestr(makedate(), "%m", False) - format += "@%m" - if '%d' not in format: - date += "@" + datestr(makedate(), "%d", False) - format += "@%d" + # add missing elements from defaults + for part in defaults: + found = [True for p in part if ("%"+p) in format] + if not found: + date += "@" + defaults[part] + format += "@%" + part[0] timetuple = time.strptime(date, format) localunixtime = int(calendar.timegm(timetuple)) @@ -1097,7 +1102,7 @@ unixtime = localunixtime + offset return unixtime, offset -def parsedate(string, formats=None): +def parsedate(string, formats=None, defaults=None): """parse a localized time string and return a (unixtime, offset) tuple. The date may be a "unixtime offset" string or in one of the specified formats.""" @@ -1109,9 +1114,22 @@ try: when, offset = map(int, string.split(' ')) except ValueError: + # fill out defaults + if not defaults: + defaults = {} + now = makedate() + for part in "d mb yY HI M S".split(): + if part not in defaults: + if part[0] in "HMS": + defaults[part] = "00" + elif part[0] in "dm": + defaults[part] = "1" + else: + defaults[part] = datestr(now, "%" + part[0], False) + for format in formats: try: - when, offset = strdate(string, format) + when, offset = strdate(string, format, defaults) except ValueError: pass else: @@ -1128,6 +1146,54 @@ raise Abort(_('impossible time zone offset: %d') % offset) return when, offset +def matchdate(date): + """Return a function that matches a given date match specifier + + Formats include: + + '{date}' match a given date to the accuracy provided + + '<{date}' on or before a given date + + '>{date}' on or after a given date + + """ + + def lower(date): + return parsedate(date, extendeddateformats)[0] + + def upper(date): + d = dict(mb="12", HI="23", M="59", S="59") + for days in "31 30 29".split(): + try: + d["d"] = days + return parsedate(date, extendeddateformats, d)[0] + except: + pass + d["d"] = "28" + return parsedate(date, extendeddateformats, d)[0] + + if date[0] == "<": + when = upper(date[1:]) + return lambda x: x <= when + elif date[0] == ">": + when = lower(date[1:]) + return lambda x: x >= when + elif date[0] == "-": + try: + days = int(date[1:]) + except ValueError: + raise Abort(_("invalid day spec: %s") % date[1:]) + when = makedate()[0] - days * 3600 * 24 + return lambda x: x <= when + elif " to " in date: + a, b = date.split(" to ") + start, stop = lower(a), upper(b) + return lambda x: x >= start and x <= stop + else: + start, stop = lower(date), upper(date) + return lambda x: x >= start and x <= stop + def shortuser(user): """Return a short representation of a user name or email address.""" f = user.find('@')