diff --git a/hgext/blackbox.py b/hgext/blackbox.py --- a/hgext/blackbox.py +++ b/hgext/blackbox.py @@ -49,6 +49,7 @@ ui as uimod, util, ) +from mercurial.utils import dateutil # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should @@ -164,7 +165,7 @@ return ui._bbinlog = True default = self.configdate('devel', 'default-date') - date = util.datestr(default, '%Y/%m/%d %H:%M:%S') + date = dateutil.datestr(default, '%Y/%m/%d %H:%M:%S') user = util.getuser() pid = '%d' % util.getpid() formattedmsg = msg[0] % msg[1:] diff --git a/hgext/convert/cvs.py b/hgext/convert/cvs.py --- a/hgext/convert/cvs.py +++ b/hgext/convert/cvs.py @@ -18,6 +18,7 @@ pycompat, util, ) +from mercurial.utils import dateutil from . import ( common, @@ -93,7 +94,7 @@ cs.comment = self.recode(cs.comment) if self.ui.configbool('convert', 'localtimezone'): cs.date = makedatetimestamp(cs.date[0]) - date = util.datestr(cs.date, '%Y-%m-%d %H:%M:%S %1%2') + date = dateutil.datestr(cs.date, '%Y-%m-%d %H:%M:%S %1%2') self.tags.update(dict.fromkeys(cs.tags, id)) files = {} diff --git a/hgext/convert/cvsps.py b/hgext/convert/cvsps.py --- a/hgext/convert/cvsps.py +++ b/hgext/convert/cvsps.py @@ -17,6 +17,7 @@ pycompat, util, ) +from mercurial.utils import dateutil pickle = util.pickle @@ -192,7 +193,7 @@ if oldlog: date = oldlog[-1].date # last commit date as a (time,tz) tuple - date = util.datestr(date, '%Y/%m/%d %H:%M:%S %1%2') + date = dateutil.datestr(date, '%Y/%m/%d %H:%M:%S %1%2') # build the CVS commandline cmd = ['cvs', '-q'] @@ -900,7 +901,7 @@ # bug-for-bug compatibility with cvsps. ui.write('---------------------\n') ui.write(('PatchSet %d \n' % cs.id)) - ui.write(('Date: %s\n' % util.datestr(cs.date, + ui.write(('Date: %s\n' % dateutil.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2'))) ui.write(('Author: %s\n' % cs.author)) ui.write(('Branch: %s\n' % (cs.branch or 'HEAD'))) diff --git a/hgext/convert/darcs.py b/hgext/convert/darcs.py --- a/hgext/convert/darcs.py +++ b/hgext/convert/darcs.py @@ -16,6 +16,7 @@ error, util, ) +from mercurial.utils import dateutil from . import common NoRepo = common.NoRepo @@ -152,8 +153,9 @@ desc = elt.findtext('name') + '\n' + elt.findtext('comment', '') # etree can return unicode objects for name, comment, and author, # so recode() is used to ensure str objects are emitted. + newdateformat = '%Y-%m-%d %H:%M:%S %1%2' return common.commit(author=self.recode(elt.get('author')), - date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), + date=dateutil.datestr(date, newdateformat), desc=self.recode(desc).strip(), parents=self.parents[rev]) diff --git a/hgext/convert/gnuarch.py b/hgext/convert/gnuarch.py --- a/hgext/convert/gnuarch.py +++ b/hgext/convert/gnuarch.py @@ -19,6 +19,7 @@ error, util, ) +from mercurial.utils import dateutil from . import common class gnuarch_source(common.converter_source, common.commandline): @@ -280,8 +281,8 @@ catlog = self.catlogparser.parsestr(data) # Commit date - self.changes[rev].date = util.datestr( - util.strdate(catlog['Standard-date'], + self.changes[rev].date = dateutil.datestr( + dateutil.strdate(catlog['Standard-date'], '%Y-%m-%d %H:%M:%S')) # Commit author diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py --- a/hgext/convert/hg.py +++ b/hgext/convert/hg.py @@ -36,6 +36,7 @@ scmutil, util, ) +from mercurial.utils import dateutil stringio = util.stringio from . import common @@ -588,7 +589,7 @@ crev = rev return common.commit(author=ctx.user(), - date=util.datestr(ctx.date(), + date=dateutil.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'), desc=ctx.description(), rev=crev, diff --git a/hgext/convert/monotone.py b/hgext/convert/monotone.py --- a/hgext/convert/monotone.py +++ b/hgext/convert/monotone.py @@ -15,6 +15,7 @@ error, util, ) +from mercurial.utils import dateutil from . import common @@ -308,9 +309,10 @@ certs = self.mtngetcerts(rev) if certs.get('suspend') == certs["branch"]: extra['close'] = 1 + dateformat = "%Y-%m-%dT%H:%M:%S" return common.commit( author=certs["author"], - date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")), + date=dateutil.datestr(util.strdate(certs["date"], dateformat)), desc=certs["changelog"], rev=rev, parents=self.mtnrun("parents", rev).splitlines(), diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py --- a/hgext/convert/p4.py +++ b/hgext/convert/p4.py @@ -14,6 +14,7 @@ error, util, ) +from mercurial.utils import dateutil from . import common @@ -346,7 +347,7 @@ parents = [] return common.commit(author=self.recode(obj["user"]), - date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), + date=dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), parents=parents, desc=desc, branch=None, rev=obj['change'], extra={"p4": obj['change'], "convert_revision": obj['change']}) diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py --- a/hgext/convert/subversion.py +++ b/hgext/convert/subversion.py @@ -16,6 +16,7 @@ util, vfs as vfsmod, ) +from mercurial.utils import dateutil from . import common @@ -912,7 +913,7 @@ branch = None cset = commit(author=author, - date=util.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), + date=dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), desc=log, parents=parents, branch=branch, diff --git a/hgext/keyword.py b/hgext/keyword.py --- a/hgext/keyword.py +++ b/hgext/keyword.py @@ -110,6 +110,7 @@ templatefilters, util, ) +from mercurial.utils import dateutil cmdtable = {} command = registrar.command(cmdtable) @@ -155,21 +156,21 @@ def utcdate(text): '''Date. Returns a UTC-date in this format: "2009/08/18 11:00:13". ''' - return util.datestr((util.parsedate(text)[0], 0), '%Y/%m/%d %H:%M:%S') + return dateutil.datestr((util.parsedate(text)[0], 0), '%Y/%m/%d %H:%M:%S') # date like in svn's $Date @templatefilter('svnisodate') def svnisodate(text): '''Date. Returns a date in this format: "2009-08-18 13:00:13 +0200 (Tue, 18 Aug 2009)". ''' - return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)') + return dateutil.datestr(text, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)') # date like in svn's $Id @templatefilter('svnutcdate') def svnutcdate(text): '''Date. Returns a UTC-date in this format: "2009-08-18 11:00:13Z". ''' - return util.datestr((util.parsedate(text)[0], 0), '%Y-%m-%d %H:%M:%SZ') + return dateutil.datestr((util.parsedate(text)[0], 0), '%Y-%m-%d %H:%M:%SZ') # make keyword tools accessible kwtools = {'hgcmd': ''} diff --git a/hgext/notify.py b/hgext/notify.py --- a/hgext/notify.py +++ b/hgext/notify.py @@ -149,6 +149,7 @@ registrar, util, ) +from mercurial.utils import dateutil # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should @@ -361,7 +362,7 @@ for k, v in headers: msg[k] = v - msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2") + msg['Date'] = dateutil.datestr(format="%a, %d %b %Y %H:%M:%S %1%2") # try to make subject line exist and be useful if not subject: diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -50,6 +50,7 @@ util, vfs as vfsmod, ) +from .utils import dateutil stringio = util.stringio # templates of common command options @@ -1506,7 +1507,7 @@ write("# HG changeset patch\n") write("# User %s\n" % ctx.user()) write("# Date %d %d\n" % ctx.date()) - write("# %s\n" % util.datestr(ctx.date())) + write("# %s\n" % dateutil.datestr(ctx.date())) if branch and branch != 'default': write("# Branch %s\n" % branch) write("# Node ID %s\n" % hex(node)) @@ -1738,7 +1739,7 @@ % scmutil.formatrevnode(self.ui, mrev, mnode), label='ui.debug log.manifest') self.ui.write(columns['user'] % ctx.user(), label='log.user') - self.ui.write(columns['date'] % util.datestr(ctx.date()), + self.ui.write(columns['date'] % dateutil.datestr(ctx.date()), label='log.date') if ctx.isunstable(): @@ -2114,7 +2115,7 @@ rev = ctx.rev() if rev in results: ui.status(_("found revision %s from %s\n") % - (rev, util.datestr(results[rev]))) + (rev, dateutil.datestr(results[rev]))) return '%d' % rev raise error.Abort(_("revision matching date not found")) diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -304,7 +304,7 @@ if ui.quiet: datefunc = util.shortdate else: - datefunc = util.datestr + datefunc = dateutil.datestr if ctx.rev() is None: def hexfn(node): if node is None: diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -73,6 +73,7 @@ util, vfs as vfsmod, ) +from .utils import dateutil release = lockmod.release @@ -560,7 +561,7 @@ else: d = util.parsedate(date) ui.write(("internal: %s %s\n") % d) - ui.write(("standard: %s\n") % util.datestr(d)) + ui.write(("standard: %s\n") % dateutil.datestr(d)) if range: m = util.matchdate(range) ui.write(("match: %s\n") % m(d[0])) diff --git a/mercurial/formatter.py b/mercurial/formatter.py --- a/mercurial/formatter.py +++ b/mercurial/formatter.py @@ -126,6 +126,7 @@ templater, util, ) +from .utils import dateutil pickle = util.pickle @@ -243,7 +244,7 @@ @staticmethod def formatdate(date, fmt): '''stringify date tuple in the given format''' - return util.datestr(date, fmt) + return dateutil.datestr(date, fmt) @staticmethod def formatdict(data, key, value, fmt, sep): '''stringify key-value pairs separated by sep''' diff --git a/mercurial/mdiff.py b/mercurial/mdiff.py --- a/mercurial/mdiff.py +++ b/mercurial/mdiff.py @@ -18,6 +18,7 @@ pycompat, util, ) +from .utils import dateutil bdiff = policy.importmod(r'bdiff') mpatch = policy.importmod(r'mpatch') @@ -259,7 +260,7 @@ aprefix = 'a/' bprefix = 'b/' - epoch = util.datestr((0, 0)) + epoch = dateutil.datestr((0, 0)) fn1 = util.pconvert(fn1) fn2 = util.pconvert(fn2) diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py --- a/mercurial/obsutil.py +++ b/mercurial/obsutil.py @@ -15,6 +15,7 @@ phases, util, ) +from .utils import dateutil class marker(object): """Wrap obsolete marker raw data""" @@ -856,11 +857,11 @@ max_date = max(dates) if min_date == max_date: - fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2') + fmtmin_date = dateutil.datestr(min_date, '%Y-%m-%d %H:%M %1%2') line.append(" (at %s)" % fmtmin_date) else: - fmtmin_date = util.datestr(min_date, '%Y-%m-%d %H:%M %1%2') - fmtmax_date = util.datestr(max_date, '%Y-%m-%d %H:%M %1%2') + fmtmin_date = dateutil.datestr(min_date, '%Y-%m-%d %H:%M %1%2') + fmtmax_date = dateutil.datestr(max_date, '%Y-%m-%d %H:%M %1%2') line.append(" (between %s and %s)" % (fmtmin_date, fmtmax_date)) return "".join(line) diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -41,6 +41,7 @@ util, vfs as vfsmod, ) +from .utils import dateutil diffhelpers = policy.importmod(r'diffhelpers') stringio = util.stringio @@ -2670,8 +2671,8 @@ def isempty(fctx): return fctx is None or fctx.size() == 0 - date1 = util.datestr(ctx1.date()) - date2 = util.datestr(ctx2.date()) + date1 = dateutil.datestr(ctx1.date()) + date2 = dateutil.datestr(ctx2.date()) gitmode = {'l': '120000', 'x': '100755', '': '100644'} diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -37,6 +37,7 @@ util, vfs as vfsmod, ) +from .utils import dateutil hg = None propertycache = util.propertycache @@ -1829,7 +1830,7 @@ if date: # git's date parser silently ignores when seconds < 1e9 # convert to ISO8601 - env['GIT_AUTHOR_DATE'] = util.datestr(date, + env['GIT_AUTHOR_DATE'] = dateutil.datestr(date, '%Y-%m-%dT%H:%M:%S %1%2') self._gitcommand(cmd, env=env) # make sure commit works otherwise HEAD might not exist under certain diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py --- a/mercurial/templatefilters.py +++ b/mercurial/templatefilters.py @@ -22,6 +22,7 @@ url, util, ) +from .utils import dateutil urlerr = util.urlerr urlreq = util.urlreq @@ -196,7 +197,7 @@ """Date. Returns the date in ISO 8601 format: "2009-08-18 13:00 +0200". """ - return util.datestr(text, '%Y-%m-%d %H:%M %1%2') + return dateutil.datestr(text, '%Y-%m-%d %H:%M %1%2') @templatefilter('isodatesec') def isodatesec(text): @@ -204,7 +205,7 @@ seconds: "2009-08-18 13:00:13 +0200". See also the rfc3339date filter. """ - return util.datestr(text, '%Y-%m-%d %H:%M:%S %1%2') + return dateutil.datestr(text, '%Y-%m-%d %H:%M:%S %1%2') def indent(text, prefix): '''indent each non-empty line of text after first with prefix.''' @@ -318,14 +319,14 @@ """Date. Returns a date using the Internet date format specified in RFC 3339: "2009-08-18T13:00:13+02:00". """ - return util.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2") + return dateutil.datestr(text, "%Y-%m-%dT%H:%M:%S%1:%2") @templatefilter('rfc822date') def rfc822date(text): """Date. Returns a date using the same format used in email headers: "Tue, 18 Aug 2009 13:00:13 +0200". """ - return util.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2") + return dateutil.datestr(text, "%a, %d %b %Y %H:%M:%S %1%2") @templatefilter('short') def short(text): diff --git a/mercurial/templater.py b/mercurial/templater.py --- a/mercurial/templater.py +++ b/mercurial/templater.py @@ -593,9 +593,9 @@ fmt = evalstring(context, mapping, args[1]) try: if fmt is None: - return util.datestr(date) + return dateutil.datestr(date) else: - return util.datestr(date, fmt) + return dateutil.datestr(date, fmt) except (TypeError, ValueError): # i18n: "date" is a keyword raise error.ParseError(_("date expects a date information")) diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -1906,45 +1906,9 @@ limit -= len(s) yield s -def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'): - """represent a (unixtime, offset) tuple as a localized time. - unixtime is seconds since the epoch, and offset is the time zone's - number of seconds away from UTC. - - >>> datestr((0, 0)) - 'Thu Jan 01 00:00:00 1970 +0000' - >>> datestr((42, 0)) - 'Thu Jan 01 00:00:42 1970 +0000' - >>> datestr((-42, 0)) - 'Wed Dec 31 23:59:18 1969 +0000' - >>> datestr((0x7fffffff, 0)) - 'Tue Jan 19 03:14:07 2038 +0000' - >>> datestr((-0x80000000, 0)) - 'Fri Dec 13 20:45:52 1901 +0000' - """ - t, tz = date or dateutil.makedate() - if "%1" in format or "%2" in format or "%z" in format: - sign = (tz > 0) and "-" or "+" - minutes = abs(tz) // 60 - q, r = divmod(minutes, 60) - format = format.replace("%z", "%1%2") - format = format.replace("%1", "%c%02d" % (sign, q)) - format = format.replace("%2", "%02d" % r) - d = t - tz - if d > 0x7fffffff: - d = 0x7fffffff - elif d < -0x80000000: - d = -0x80000000 - # Never use time.gmtime() and datetime.datetime.fromtimestamp() - # because they use the gmtime() system call which is buggy on Windows - # for negative values. - t = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=d) - s = encoding.strtolocal(t.strftime(encoding.strfromlocal(format))) - return s - def shortdate(date=None): """turn (timestamp, tzoff) tuple into iso 8631 date.""" - return datestr(date, format='%Y-%m-%d') + return dateutil.datestr(date, format='%Y-%m-%d') def parsetimezone(s): """find a trailing timezone, if any, in string, and return a @@ -2063,7 +2027,7 @@ b = "0" # this piece is for matching the generic end to today's date - n = datestr(now, "%" + part[0:1]) + n = dateutil.datestr(now, "%" + part[0:1]) defaults[part] = (b, n) @@ -3905,3 +3869,9 @@ nouideprecwarn(msg, "4.6") return dateutil.makedate(*args, **kwargs) +def datestr(*args, **kwargs): + msg = ("'util.datestr' is deprecated, " + "use 'utils.dateutil.datestr'") + nouideprecwarn(msg, "4.6") + return dateutil.datestr(*args, **kwargs) + diff --git a/mercurial/utils/dateutil.py b/mercurial/utils/dateutil.py --- a/mercurial/utils/dateutil.py +++ b/mercurial/utils/dateutil.py @@ -12,6 +12,7 @@ from ..i18n import _ from .. import ( + encoding, error, ) @@ -70,3 +71,38 @@ tz = delta.days * 86400 + delta.seconds return timestamp, tz +def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'): + """represent a (unixtime, offset) tuple as a localized time. + unixtime is seconds since the epoch, and offset is the time zone's + number of seconds away from UTC. + + >>> datestr((0, 0)) + 'Thu Jan 01 00:00:00 1970 +0000' + >>> datestr((42, 0)) + 'Thu Jan 01 00:00:42 1970 +0000' + >>> datestr((-42, 0)) + 'Wed Dec 31 23:59:18 1969 +0000' + >>> datestr((0x7fffffff, 0)) + 'Tue Jan 19 03:14:07 2038 +0000' + >>> datestr((-0x80000000, 0)) + 'Fri Dec 13 20:45:52 1901 +0000' + """ + t, tz = date or makedate() + if "%1" in format or "%2" in format or "%z" in format: + sign = (tz > 0) and "-" or "+" + minutes = abs(tz) // 60 + q, r = divmod(minutes, 60) + format = format.replace("%z", "%1%2") + format = format.replace("%1", "%c%02d" % (sign, q)) + format = format.replace("%2", "%02d" % r) + d = t - tz + if d > 0x7fffffff: + d = 0x7fffffff + elif d < -0x80000000: + d = -0x80000000 + # Never use time.gmtime() and datetime.datetime.fromtimestamp() + # because they use the gmtime() system call which is buggy on Windows + # for negative values. + t = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=d) + s = encoding.strtolocal(t.strftime(encoding.strfromlocal(format))) + return s