]> arthur.barton.de Git - bup.git/commitdiff
Get TZ offset from C localtime, given tm_gmtoff 0.27-rc4
authorRob Browning <rlb@defaultvalue.org>
Sat, 28 Mar 2015 20:09:47 +0000 (15:09 -0500)
committerRob Browning <rlb@defaultvalue.org>
Sat, 28 Mar 2015 20:09:47 +0000 (15:09 -0500)
If we detect that struct tm contains tm_gmtoff, use the system
localtime() to compute timezone offsets.  This may help fix problems on
platforms where Python strftime "%z" doesn't report accurate timzeone
information.

Thanks to Patrick Rouleau for reporting just such a problem on Cygwin.

Signed-off-by: Rob Browning <rlb@defaultvalue.org>
Tested-by: Rob Browning <rlb@defaultvalue.org>
config/configure
lib/bup/_helpers.c
lib/bup/git.py
lib/bup/helpers.py

index d6156d25b565fd77f4301ae5f02d1280e4fb0ff5..ccc02b20559da2a8da40068f51b1708ed2f38e9a 100755 (executable)
@@ -74,4 +74,6 @@ AC_CHECK_FIELD stat st_atimensec sys/types.h sys/stat.h unistd.h
 AC_CHECK_FIELD stat st_mtimensec sys/types.h sys/stat.h unistd.h
 AC_CHECK_FIELD stat st_ctimensec sys/types.h sys/stat.h unistd.h
 
+AC_CHECK_FIELD tm tm_gmtoff time.h
+
 AC_OUTPUT config.vars
index 59f0fa381558e255a37f8b7059881f09feb73229..caa5c021c183d2a98f5d8f74e4fe2e44f71d4ec7 100644 (file)
 #include <sys/ioctl.h>
 #endif
 
+#ifdef HAVE_TM_TM_GMTOFF
+#include <time.h>
+#endif
+
 #include "bupsplit.h"
 
 #if defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS)
@@ -1297,6 +1301,30 @@ static PyObject *bup_fstat(PyObject *self, PyObject *args)
 }
 
 
+#ifdef HAVE_TM_TM_GMTOFF
+static PyObject *bup_localtime(PyObject *self, PyObject *args)
+{
+    long long lltime;
+    time_t ttime;
+    if (!PyArg_ParseTuple(args, "L", &lltime))
+       return NULL;
+    if (!INTEGRAL_ASSIGNMENT_FITS(&ttime, lltime))
+        return PyErr_Format(PyExc_OverflowError, "time value too large");
+
+    struct tm tm;
+    if(localtime_r(&ttime, &tm) == NULL)
+        return PyErr_SetFromErrno(PyExc_OSError);
+
+    // Match the Python struct_time values.
+    return Py_BuildValue("[i,i,i,i,i,i,i,i,i,i,s]",
+                         1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
+                         tm.tm_hour, tm.tm_min, tm.tm_sec,
+                         tm.tm_wday, tm.tm_yday + 1,
+                         tm.tm_isdst, tm.tm_gmtoff, tm.tm_zone);
+}
+#endif /* def HAVE_TM_TM_GMTOFF */
+
+
 static PyMethodDef helper_methods[] = {
     { "write_sparsely", bup_write_sparsely, METH_VARARGS,
       "Write buf excepting zeros at the end. Return trailing zero count." },
@@ -1355,6 +1383,10 @@ static PyMethodDef helper_methods[] = {
       "Extended version of lstat." },
     { "fstat", bup_fstat, METH_VARARGS,
       "Extended version of fstat." },
+#ifdef HAVE_TM_TM_GMTOFF
+    { "localtime", bup_localtime, METH_VARARGS,
+      "Return struct_time elements plus the timezone offset and name." },
+#endif
     { NULL, NULL, 0, NULL },  // sentinel
 };
 
index afd1b3614816b5780fe1d0a6beece597e14dd563..2fc155f6a49ed8a81ef5b5580d7c19fa231334f4 100644 (file)
@@ -761,7 +761,7 @@ class PackWriter:
 
 
 def _git_date(date):
-    return '%d %s' % (date, time.strftime('%z', time.localtime(date)))
+    return '%d %s' % (date, utc_offset_str(date))
 
 
 def _gitenv(repo_dir = None):
index c15b357733b378105a160ec8e829f92bdfe0bdaa..bcaec1bf2daaab2201b2df43701b4c65f00f9b5f 100644 (file)
@@ -1,14 +1,13 @@
 """Helper functions and classes for bup."""
 
+from collections import namedtuple
 from ctypes import sizeof, c_void_p
 from os import environ
 from contextlib import contextmanager
 import sys, os, pwd, subprocess, errno, socket, select, mmap, stat, re, struct
-import hashlib, heapq, operator, time, grp, tempfile
+import hashlib, heapq, math, operator, time, grp, tempfile
 
 from bup import _helpers
-import bup._helpers as _helpers
-import math
 
 # This function should really be in helpers, not in bup.options.  But we
 # want options.py to be standalone so people can include it in other projects.
@@ -987,4 +986,37 @@ def grafted_path_components(graft_points, path):
             return result
     return path_components(clean_path)
 
+
 Sha1 = hashlib.sha1
+
+
+_localtime = getattr(_helpers, 'localtime', None)
+
+if _localtime:
+    bup_time = namedtuple('bup_time', ['tm_year', 'tm_mon', 'tm_mday',
+                                       'tm_hour', 'tm_min', 'tm_sec',
+                                       'tm_wday', 'tm_yday',
+                                       'tm_isdst', 'tm_gmtoff', 'tm_zone'])
+
+# Define a localtime() that returns bup_time when possible.  Note:
+# this means that any helpers.localtime() results may need to be
+# passed through to_py_time() before being passed to python's time
+# module, which doesn't appear willing to ignore the extra items.
+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.'
+        off = localtime(t).tm_gmtoff
+        hrs = off / 60 / 60
+        return "%+03d%02d" % (hrs, abs(off - (hrs * 60 * 60)))
+    def to_py_time(x):
+        if isinstance(x, time.struct_time):
+            return x
+        return time.struct_time(x[:9])
+else:
+    localtime = time.localtime
+    def utc_offset_str(t):
+        return time.strftime('%z', localtime(t))
+    def to_py_time(x):
+        return x