]> arthur.barton.de Git - bup.git/commitdiff
Fix utc_offset_str for fractional TZs
authorRob Browning <rlb@defaultvalue.org>
Sat, 5 Dec 2015 19:41:36 +0000 (13:41 -0600)
committerRob Browning <rlb@defaultvalue.org>
Sat, 12 Dec 2015 17:16:50 +0000 (11:16 -0600)
Previously, for fractional offsets like TZ=FOO+3:3 (where the offset
is not an integer number of hours), utc_offset_str() would return a
large, incorrect integer value.  Adjust it to handle arbitrary
offsets, and document that it truncates any fractional seconds of the
offset.

Before this fix, whenever bup was operating with a fractional offset
(e.g. TZ=Australia/Adelaide), it wrote commits (i.e. saves) that it
won't be able to read.  Attempts to read them will fail with
"Exception: cannot parse commit".

Thanks to David Kettler for reporting the problem, and proposing an
alternate fix.

Reviewed-by: David Kettler <kettler@internode.on.net>
Tested-by: David Kettler <kettler@internode.on.net>
[rlb@defaultvalue.org: changed / to // for Python 3 compat]
Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
lib/bup/helpers.py
lib/bup/t/thelpers.py

index e7fbc5b8992a18433d3f54cc5241c8adac5de18c..3427e0397fe4e86cb31ed4949ad7aea951582bca 100644 (file)
@@ -1049,10 +1049,15 @@ if _localtime:
     def localtime(time):
         return bup_time(*_helpers.localtime(time))
     def utc_offset_str(t):
-        'Return the local offset from UTC as "+hhmm" or "-hhmm" for time t.'
+        """Return the local offset from UTC as "+hhmm" or "-hhmm" for time t.
+        If the current UTC offset does not represent an integer number
+        of minutes, the fractional component will be truncated."""
         off = localtime(t).tm_gmtoff
-        hrs = off / 60 / 60
-        return "%+03d%02d" % (hrs, abs(off - (hrs * 60 * 60)))
+        # Note: // doesn't truncate like C for negative values, it rounds down.
+        offmin = abs(off) // 60
+        m = offmin % 60
+        h = (offmin - m) // 60
+        return "%+03d%02d" % (-h if off < 0 else h, m)
     def to_py_time(x):
         if isinstance(x, time.struct_time):
             return x
index 79eb4af444dd82380aa931bcb042984462035aaf..10ebce1b2c6bdb4f3f5ceca1c5075afeefbe733e 100644 (file)
@@ -179,3 +179,33 @@ def test_atomically_replaced_file():
 
     if wvfailure_count() == initial_failures:
         subprocess.call(['rm', '-rf', tmpdir])
+
+
+@wvtest
+def test_utc_offset_str():
+    tz = os.environ.get('TZ')
+    try:
+        os.environ['TZ'] = 'FOO+0:00'
+        WVPASSEQ(utc_offset_str(0), '+0000')
+        os.environ['TZ'] = 'FOO+1:00'
+        WVPASSEQ(utc_offset_str(0), '-0100')
+        os.environ['TZ'] = 'FOO-1:00'
+        WVPASSEQ(utc_offset_str(0), '+0100')
+        os.environ['TZ'] = 'FOO+3:3'
+        WVPASSEQ(utc_offset_str(0), '-0303')
+        os.environ['TZ'] = 'FOO-3:3'
+        WVPASSEQ(utc_offset_str(0), '+0303')
+        # Offset is not an integer number of minutes
+        os.environ['TZ'] = 'FOO+3:3:3'
+        WVPASSEQ(utc_offset_str(1), '-0303')
+        os.environ['TZ'] = 'FOO-3:3:3'
+        WVPASSEQ(utc_offset_str(1), '+0303')
+        WVPASSEQ(utc_offset_str(314159), '+0303')
+    finally:
+        if tz:
+            os.environ['TZ'] = tz
+        else:
+            try:
+                del os.environ['TZ']
+            except KeyError:
+                pass