date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513)
authorFlorent Gallaire <fgallaire@gmail.com>
Fri, 08 Apr 2016 14:11:03 +0200
changeset 28825 87c6ad2251d8
parent 28824 9d31582dd636
child 28826 59dd920c0ddc
date: reallow negative timestamp, fix for Windows buggy gmtime() (issue2513) DVCS are very useful to store various texts (as legislation) written before Unix epoch. Fri, 13 Dec 1901 is a nice gain over Thu, 01 Jan 1970. Revert dd24f3e7ca9e and e1002cf9fe54, fix c208dcd0f709. Add tests.
mercurial/util.py
tests/test-commit.t
--- a/mercurial/util.py	Wed Apr 06 19:08:04 2016 +0000
+++ b/mercurial/util.py	Fri Apr 08 14:11:03 2016 +0200
@@ -1585,9 +1585,6 @@
     number of seconds away from UTC. if timezone is false, do not
     append time zone to string."""
     t, tz = date or makedate()
-    if t < 0:
-        t = 0   # time.gmtime(lt) fails on Windows for lt < -43200
-        tz = 0
     if "%1" in format or "%2" in format or "%z" in format:
         sign = (tz > 0) and "-" or "+"
         minutes = abs(tz) // 60
@@ -1595,12 +1592,16 @@
         format = format.replace("%z", "%1%2")
         format = format.replace("%1", "%c%02d" % (sign, q))
         format = format.replace("%2", "%02d" % r)
-    try:
-        t = time.gmtime(float(t) - tz)
-    except ValueError:
-        # time was out of range
-        t = time.gmtime(sys.maxint)
-    s = time.strftime(format, t)
+    d = t - tz
+    if d > 0x7fffffff:
+        d = 0x7fffffff
+    elif d < -0x7fffffff:
+        d = -0x7fffffff
+    # 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 = t.strftime(format)
     return s
 
 def shortdate(date=None):
@@ -1721,8 +1722,6 @@
     # to UTC+14
     if abs(when) > 0x7fffffff:
         raise Abort(_('date exceeds 32 bits: %d') % when)
-    if when < 0:
-        raise Abort(_('negative date value: %d') % when)
     if offset < -50400 or offset > 43200:
         raise Abort(_('impossible time zone offset: %d') % offset)
     return when, offset
--- a/tests/test-commit.t	Wed Apr 06 19:08:04 2016 +0000
+++ b/tests/test-commit.t	Fri Apr 08 14:11:03 2016 +0200
@@ -27,8 +27,21 @@
   $ hg commit -d '111111111111 0' -m commit-7
   abort: date exceeds 32 bits: 111111111111
   [255]
-  $ hg commit -d '-7654321 3600' -m commit-7
-  abort: negative date value: -7654321
+  $ hg commit -d '-111111111111 0' -m commit-7
+  abort: date exceeds 32 bits: -111111111111
+  [255]
+  $ echo foo >> foo
+  $ hg commit -d '1901-12-13 20:45:53 +0000' -m commit-7-2
+  $ echo foo >> foo
+  $ hg commit -d '-2147483647 0' -m commit-7-3
+  $ hg log -T '{rev} {date|isodatesec}\n' -l2
+  3 1901-12-13 20:45:53 +0000
+  2 1901-12-13 20:45:53 +0000
+  $ hg commit -d '1901-12-13 20:45:52 +0000' -m commit-7
+  abort: date exceeds 32 bits: -2147483648
+  [255]
+  $ hg commit -d '-2147483648 0' -m commit-7
+  abort: date exceeds 32 bits: -2147483648
   [255]
 
 commit added file that has been deleted
@@ -54,7 +67,7 @@
   dir/file
   committing manifest
   committing changelog
-  committed changeset 2:d2a76177cb42
+  committed changeset 4:76aab26859d7
 
   $ echo > dir.file
   $ hg add
@@ -78,7 +91,7 @@
   dir/file
   committing manifest
   committing changelog
-  committed changeset 3:1cd62a2d8db5
+  committed changeset 5:9a50557f1baf
   $ cd ..
 
   $ hg commit -m commit-14 does-not-exist
@@ -102,7 +115,7 @@
   dir/file
   committing manifest
   committing changelog
-  committed changeset 4:49176991390e
+  committed changeset 6:4b4c75bf422d
 
 An empty date was interpreted as epoch origin