comparison mercurial/util.py @ 28825:87c6ad2251d8

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.
author Florent Gallaire <fgallaire@gmail.com>
date Fri, 08 Apr 2016 14:11:03 +0200
parents 6041fb8f2da8
children 59dd920c0ddc
comparison
equal deleted inserted replaced
28824:9d31582dd636 28825:87c6ad2251d8
1583 """represent a (unixtime, offset) tuple as a localized time. 1583 """represent a (unixtime, offset) tuple as a localized time.
1584 unixtime is seconds since the epoch, and offset is the time zone's 1584 unixtime is seconds since the epoch, and offset is the time zone's
1585 number of seconds away from UTC. if timezone is false, do not 1585 number of seconds away from UTC. if timezone is false, do not
1586 append time zone to string.""" 1586 append time zone to string."""
1587 t, tz = date or makedate() 1587 t, tz = date or makedate()
1588 if t < 0:
1589 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
1590 tz = 0
1591 if "%1" in format or "%2" in format or "%z" in format: 1588 if "%1" in format or "%2" in format or "%z" in format:
1592 sign = (tz > 0) and "-" or "+" 1589 sign = (tz > 0) and "-" or "+"
1593 minutes = abs(tz) // 60 1590 minutes = abs(tz) // 60
1594 q, r = divmod(minutes, 60) 1591 q, r = divmod(minutes, 60)
1595 format = format.replace("%z", "%1%2") 1592 format = format.replace("%z", "%1%2")
1596 format = format.replace("%1", "%c%02d" % (sign, q)) 1593 format = format.replace("%1", "%c%02d" % (sign, q))
1597 format = format.replace("%2", "%02d" % r) 1594 format = format.replace("%2", "%02d" % r)
1598 try: 1595 d = t - tz
1599 t = time.gmtime(float(t) - tz) 1596 if d > 0x7fffffff:
1600 except ValueError: 1597 d = 0x7fffffff
1601 # time was out of range 1598 elif d < -0x7fffffff:
1602 t = time.gmtime(sys.maxint) 1599 d = -0x7fffffff
1603 s = time.strftime(format, t) 1600 # Never use time.gmtime() and datetime.datetime.fromtimestamp()
1601 # because they use the gmtime() system call which is buggy on Windows
1602 # for negative values.
1603 t = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=d)
1604 s = t.strftime(format)
1604 return s 1605 return s
1605 1606
1606 def shortdate(date=None): 1607 def shortdate(date=None):
1607 """turn (timestamp, tzoff) tuple into iso 8631 date.""" 1608 """turn (timestamp, tzoff) tuple into iso 8631 date."""
1608 return datestr(date, format='%Y-%m-%d') 1609 return datestr(date, format='%Y-%m-%d')
1719 # time zone offset. values must fit in signed 32 bits for 1720 # time zone offset. values must fit in signed 32 bits for
1720 # current 32-bit linux runtimes. timezones go from UTC-12 1721 # current 32-bit linux runtimes. timezones go from UTC-12
1721 # to UTC+14 1722 # to UTC+14
1722 if abs(when) > 0x7fffffff: 1723 if abs(when) > 0x7fffffff:
1723 raise Abort(_('date exceeds 32 bits: %d') % when) 1724 raise Abort(_('date exceeds 32 bits: %d') % when)
1724 if when < 0:
1725 raise Abort(_('negative date value: %d') % when)
1726 if offset < -50400 or offset > 43200: 1725 if offset < -50400 or offset > 43200:
1727 raise Abort(_('impossible time zone offset: %d') % offset) 1726 raise Abort(_('impossible time zone offset: %d') % offset)
1728 return when, offset 1727 return when, offset
1729 1728
1730 def matchdate(date): 1729 def matchdate(date):