On Fri, Jun 14, 2019 at 12:43:32PM +1200, Tom Ryder via vim_dev wrote:
On Thu, Jun 13, 2019 at 08:40:27PM +0200, Bram Moolenaar wrote:
Can you make a patch that adds a function to call localtime_r() and keeps the current value of $TZ, and calls tzset() only when it changes?

Yes, I think so.  I'll attempt that later today.  Thanks.

Attached is another patch attempting this. I'm happy to make any required changes.

--
Tom Ryder <https://sanctum.geek.nz/>

--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- You received this message because you are subscribed to the Google Groups "vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20190615125842.GA20090%40conan.
For more options, visit https://groups.google.com/d/optout.
>From 43784c9d367b3b2aaf01c83f524d53f5ba92db26 Mon Sep 17 00:00:00 2001
From: Tom Ryder <[email protected]>
Date: Sun, 16 Jun 2019 00:11:56 +1200
Subject: [PATCH] Add localtime/tzset abstraction: vim_localtime()

Patch 8.1.1313 (tag v8.1.1313, commit 63d2555) replaces calls to
localtime(3) with the re-entrant localtime_r(3) if available.  The
POSIX specification for localtime_r(3)'s behavior with respect to
timezones differs from that for localtime(3).  To quote the
specification:

> The localtime() function ... acts as if it called tzset(3) and sets
> the external variables tzname with information about the current
> timezone, timezone with the difference between Coordinated Universal
> Time (UTC) and local standard time in seconds, and daylight to
> a nonzero value if daylight savings time rules apply during some part
> of the year. ... The localtime_r() function ... need not set tzname,
> timezone, and daylight.

The last sentence is most relevant here.  It suggests that
implementations of localtime_r(3) need not update the timezone variables
with respect to the TZ environment variable.  This would mean that
changes to that environment variable while the process is running may
not influence the time information returned by localtime_r(3) with
respect to the desired timezone.

Indeed, on Debian GNU/Linux with GNU libc 2.24-11-deb9u4, successive
calls to the Vim function strftime() with different values for $TZ as
applied with :let exhibit confusing behavior after v8.3.131:

    :let $TZ = "UTC" | echo $TZ.' -> '.strftime("%c")
    UTC -> Wed 12 Jun 2019 04:10:29 UTC
    :let $TZ = "Pacific/Auckland" | echo $TZ.' -> '.strftime("%c")
    Pacific/Auckland -> Wed 12 Jun 2019 04:10:32 UTC

Note that neither the hour nor the reported timezone changes in the
stftime() output between invocations, even though the value of the TZ
environment value itself does change.

This patch adds an abstraction vim_localtime() in a new file datetime.c,
with the same type signatures as localtime_r(3).  If the re-entrant
localtime_r(3) is available, a static cache of the value of the TZ
environment variable is applied to check whether $TZ differs between
successive calls to vim_localtime(), and to run tzset(3) accordingly if
available.
---
 Filelist                       |  1 +
 src/Make_cyg_ming.mak          |  1 +
 src/Make_dice.mak              |  4 ++
 src/Make_manx.mak              |  6 +++
 src/Make_morph.mak             |  1 +
 src/Make_mvc.mak               |  4 ++
 src/Make_sas.mak               |  5 +++
 src/Make_vms.mms               | 14 ++++---
 src/Makefile                   | 16 ++++++--
 src/README.md                  |  1 +
 src/auto/configure             |  2 +-
 src/config.h.in                |  1 +
 src/configure.ac               |  2 +-
 src/datetime.c                 | 74 ++++++++++++++++++++++++++++++++++
 src/datetime.h                 | 16 ++++++++
 src/evalfunc.c                 |  8 +---
 src/memline.c                  |  8 +---
 src/proto/datetime.pro         |  3 ++
 src/testdir/test_functions.vim | 24 +++++++++++
 src/undo.c                     |  8 +---
 src/vim.h                      |  1 +
 21 files changed, 169 insertions(+), 31 deletions(-)
 create mode 100644 src/datetime.c
 create mode 100644 src/datetime.h
 create mode 100644 src/proto/datetime.pro

diff --git a/Filelist b/Filelist
index 99e10048f..e9887c1db 100644
--- a/Filelist
+++ b/Filelist
@@ -25,6 +25,7 @@ SRC_ALL =     \
                src/charset.c \
                src/crypt.c \
                src/crypt_zip.c \
+               src/datetime.c \
                src/debugger.c \
                src/dict.c \
                src/diff.c \
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index f47981216..07384d7fc 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -701,6 +701,7 @@ OBJ = \
        $(OUTDIR)/charset.o \
        $(OUTDIR)/crypt.o \
        $(OUTDIR)/crypt_zip.o \
+       $(OUTDIR)/datetime.o \
        $(OUTDIR)/debugger.o \
        $(OUTDIR)/dict.o \
        $(OUTDIR)/diff.o \
diff --git a/src/Make_dice.mak b/src/Make_dice.mak
index 440955eb3..5c30656c3 100644
--- a/src/Make_dice.mak
+++ b/src/Make_dice.mak
@@ -34,6 +34,7 @@ SRC = \
        charset.c \
        crypt.c \
        crypt_zip.c \
+       datetime.c \
        debugger.c \
        dict.c \
        diff.c \
@@ -97,6 +98,7 @@ OBJ = o/arabic.o \
        o/charset.o \
        o/crypt.o \
        o/crypt_zip.o \
+       o/datetime.o \
        o/debugger.o \
        o/dict.o \
        o/diff.o \
@@ -187,6 +189,8 @@ o/crypt.o:  crypt.c  $(SYMS)
 
 o/crypt_zip.o: crypt_zip.c  $(SYMS)
 
+o/datetime.o:  datetime.c  datetime.h  $(SYMS)
+
 o/debugger.o:  debugger.c  $(SYMS)
 
 o/dict.o:      dict.c  $(SYMS)
diff --git a/src/Make_manx.mak b/src/Make_manx.mak
index 211d8cceb..3956a7a80 100644
--- a/src/Make_manx.mak
+++ b/src/Make_manx.mak
@@ -44,6 +44,7 @@ SRC = arabic.c \
        charset.c \
        crypt.c \
        crypt_zip.c \
+       datetime.c \
        debugger.c \
        dict.c \
        diff.c \
@@ -109,6 +110,7 @@ OBJ =       obj/arabic.o \
        obj/charset.o \
        obj/crypt.o \
        obj/crypt_zip.o \
+       obj/datetime.o \
        obj/debugger.o \
        obj/dict.o \
        obj/diff.o \
@@ -172,6 +174,7 @@ PRO =       proto/arabic.pro \
        proto/charset.pro \
        proto/crypt.pro \
        proto/crypt_zip.pro \
+       proto/datetime.pro \
        proto/debugger.pro \
        proto/dict.pro \
        proto/diff.pro \
@@ -295,6 +298,9 @@ obj/crypt.o:        crypt.c
 obj/crypt_zip.o: crypt_zip.c
        $(CCSYM) $@ crypt_zip.c
 
+obj/datetime.o:        datetime.c datetime.h
+       $(CCSYM) $@ datetime.c
+
 obj/debugger.o:        debugger.c
        $(CCSYM) $@ debugger.c
 
diff --git a/src/Make_morph.mak b/src/Make_morph.mak
index 1eb5ff52d..ece12ea51 100644
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -32,6 +32,7 @@ SRC = arabic.c                                                
\
        charset.c                                               \
        crypt.c                                                 \
        crypt_zip.c                                             \
+       datetime.c                                              \
        debugger.c                                              \
        dict.c                                                  \
        diff.c                                                  \
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index c6f9b25a0..7ea49258c 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -704,6 +704,7 @@ OBJ = \
        $(OUTDIR)\charset.obj \
        $(OUTDIR)\crypt.obj \
        $(OUTDIR)\crypt_zip.obj \
+       $(OUTDIR)\datetime.obj \
        $(OUTDIR)\debugger.obj \
        $(OUTDIR)\dict.obj \
        $(OUTDIR)\diff.obj \
@@ -1420,6 +1421,8 @@ $(OUTDIR)/crypt.obj:      $(OUTDIR) crypt.c  $(INCL)
 
 $(OUTDIR)/crypt_zip.obj: $(OUTDIR) crypt_zip.c  $(INCL)
 
+$(OUTDIR)/datetime.obj:        $(OUTDIR) datetime.c  datetime.h  $(INCL)
+
 $(OUTDIR)/debugger.obj:        $(OUTDIR) debugger.c  $(INCL)
 
 $(OUTDIR)/dict.obj:    $(OUTDIR) dict.c  $(INCL)
@@ -1710,6 +1713,7 @@ proto.h: \
        proto/charset.pro \
        proto/crypt.pro \
        proto/crypt_zip.pro \
+       proto/datetime.pro \
        proto/debugger.pro \
        proto/dict.pro \
        proto/diff.pro \
diff --git a/src/Make_sas.mak b/src/Make_sas.mak
index 7090119d7..878f39b68 100644
--- a/src/Make_sas.mak
+++ b/src/Make_sas.mak
@@ -97,6 +97,7 @@ SRC = \
        charset.c \
        crypt.c \
        crypt_zip.c \
+       datetime.c \
        debugger.c \
        dict.c \
        diff.c \
@@ -161,6 +162,7 @@ OBJ = \
        charset.o \
        crypt.o \
        crypt_zip.o \
+       datetime.o \
        debugger.o \
        dict.o \
        diff.o \
@@ -225,6 +227,7 @@ PRO = \
        proto/charset.pro \
        proto/crypt.pro \
        proto/crypt_zip.pro \
+       proto/datetime.pro \
        proto/debugger.pro \
        proto/dict.pro \
        proto/diff.pro \
@@ -351,6 +354,8 @@ crypt.o:            crypt.c
 proto/crypt.pro:       crypt.c
 crypt_zip.o:           crypt_zip.c
 proto/crypt_zip.pro:   crypt_zip.c
+datetime.o:            datetime.c datetime.h
+proto/datetime.pro:    datetime.c datetime.h
 debugger.o:            debugger.c
 proto/debugger.pro:    debugger.c
 dict.o:                        dict.c
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index f01d325c0..bda8271e1 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -308,7 +308,7 @@ ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \
           $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB)
 
 SRC =  arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c change.c 
charset.c \
-       crypt.c crypt_zip.c debugger.c dict.c diff.c digraph.c edit.c eval.c \
+       crypt.c crypt_zip.c datetime.c debugger.c dict.c diff.c digraph.c 
edit.c eval.c \
        evalfunc.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c \
        if_cscope.c if_xcmdsrv.c fileio.c findfile.c fold.c getchar.c \
        hardcopy.c hashtab.c indent.c insexpand.c json.c list.c main.c mark.c \
@@ -321,7 +321,7 @@ SRC =       arabic.c autocmd.c beval.c blob.c blowfish.c 
buffer.c change.c charset.c \
        $(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC) $(XDIFF_SRC)
 
 OBJ =  arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj 
change.obj \
-       charset.obj crypt.obj crypt_zip.obj debugger.obj dict.obj diff.obj \
+       charset.obj crypt.obj crypt_zip.obj datetime.obj debugger.obj dict.obj 
diff.obj \
        digraph.obj edit.obj eval.obj evalfunc.obj ex_cmds.obj ex_cmds2.obj \
        ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj if_xcmdsrv.obj \
        fileio.obj findfile.obj fold.obj getchar.obj hardcopy.obj hashtab.obj \
@@ -526,6 +526,10 @@ crypt_zip.obj : crypt_zip.c vim.h [.auto]config.h 
feature.h os_unix.h \
  ascii.h keymap.h term.h macros.h option.h structs.h \
  regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
  proto.h globals.h
+datetime.obj : datetime.c vim.h [.auto]config.h feature.h os_unix.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h \
+ regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
+ proto.h globals.h version.h datetime.h
 debugger.obj : debugger.c vim.h [.auto]config.h feature.h os_unix.h \
  ascii.h keymap.h term.h macros.h structs.h regexp.h \
  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
@@ -553,7 +557,7 @@ eval.obj : eval.c vim.h [.auto]config.h feature.h os_unix.h 
  \
 evalfunc.obj : evalfunc.c vim.h [.auto]config.h feature.h os_unix.h \
  ascii.h keymap.h term.h macros.h option.h structs.h \
  regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
- proto.h globals.h version.h
+ proto.h globals.h version.h datetime.h
 ex_cmds.obj : ex_cmds.c vim.h [.auto]config.h feature.h os_unix.h \
  ascii.h keymap.h term.h macros.h structs.h regexp.h \
  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
@@ -635,7 +639,7 @@ memfile.obj : memfile.c vim.h [.auto]config.h feature.h 
os_unix.h \
 memline.obj : memline.c vim.h [.auto]config.h feature.h os_unix.h \
  ascii.h keymap.h term.h macros.h structs.h regexp.h \
  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
- globals.h
+ globals.h datetime.h
 menu.obj : menu.c vim.h [.auto]config.h feature.h os_unix.h   \
  ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
  [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
@@ -750,7 +754,7 @@ ui.obj : ui.c vim.h [.auto]config.h feature.h os_unix.h   \
 
 undo.obj : undo.c vim.h [.auto]config.h feature.h os_unix.h   \
  ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
- [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h datetime.h \
 
 usercmd.obj : usercmd.c vim.h [.auto]config.h feature.h os_unix.h \
  ascii.h keymap.h term.h macros.h option.h structs.h \
diff --git a/src/Makefile b/src/Makefile
index 9c4a42893..b30324a65 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1585,6 +1585,7 @@ BASIC_SRC = \
        charset.c \
        crypt.c \
        crypt_zip.c \
+       datetime.c \
        debugger.c \
        dict.c \
        diff.c \
@@ -1704,6 +1705,7 @@ OBJ_COMMON = \
        objects/blowfish.o \
        objects/crypt.o \
        objects/crypt_zip.o \
+       objects/datetime.o \
        objects/debugger.o \
        objects/dict.o \
        objects/diff.o \
@@ -1836,6 +1838,7 @@ PRO_AUTO = \
        charset.pro \
        crypt.pro \
        crypt_zip.pro \
+       datetime.pro \
        debugger.pro \
        dict.pro \
        diff.pro \
@@ -2991,6 +2994,9 @@ objects/crypt.o: crypt.c
 objects/crypt_zip.o: crypt_zip.c
        $(CCC) -o $@ crypt_zip.c
 
+objects/datetime.o: datetime.c datetime.h
+       $(CCC) -o $@ datetime.c
+
 objects/debugger.o: debugger.c
        $(CCC) -o $@ debugger.c
 
@@ -3469,6 +3475,10 @@ objects/crypt_zip.o: crypt_zip.c vim.h protodef.h 
auto/config.h feature.h \
  os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
  proto.h globals.h
+objects/datetime.o: datetime.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
+ proto.h globals.h datetime.h
 objects/debugger.o: debugger.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
@@ -3496,7 +3506,7 @@ objects/eval.o: eval.c vim.h protodef.h auto/config.h 
feature.h os_unix.h \
 objects/evalfunc.o: evalfunc.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
- proto.h globals.h version.h
+ proto.h globals.h version.h datetime.h
 objects/ex_cmds.o: ex_cmds.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
@@ -3580,7 +3590,7 @@ objects/memfile.o: memfile.c vim.h protodef.h 
auto/config.h feature.h os_unix.h
 objects/memline.o: memline.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
- proto.h globals.h
+ proto.h globals.h datetime.h
 objects/menu.o: menu.c vim.h protodef.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
@@ -3702,7 +3712,7 @@ objects/ui.o: ui.c vim.h protodef.h auto/config.h 
feature.h os_unix.h \
 objects/undo.o: undo.c vim.h protodef.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
- proto.h globals.h
+ proto.h globals.h datetime.h
 objects/usercmd.o: usercmd.c vim.h protodef.h auto/config.h feature.h 
os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
diff --git a/src/README.md b/src/README.md
index ff9f93ac6..f91170287 100644
--- a/src/README.md
+++ b/src/README.md
@@ -26,6 +26,7 @@ File name | Description
 autocmd.c      | autocommands
 buffer.c       | manipulating buffers (loaded files)
 change.c       | handling changes to text
+datetime.c     | date and time functions
 debugger.c     | vim script debugger
 diff.c         | diff mode (vimdiff)
 eval.c         | expression evaluation
diff --git a/src/auto/configure b/src/auto/configure
index c326abf16..8dcad0bb8 100755
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -12569,7 +12569,7 @@ for ac_func in fchdir fchown fchmod fsync getcwd 
getpseudotty \
        memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
        getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
        sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
-       strnicmp strpbrk strtol tgetent towlower towupper iswupper \
+       strnicmp strpbrk strtol tgetent towlower towupper iswupper tzset \
        usleep utime utimes mblen ftruncate unsetenv posix_openpt
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
diff --git a/src/config.h.in b/src/config.h.in
index c1ced6fe9..f9ae0bbf3 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -217,6 +217,7 @@
 #undef HAVE_TOWLOWER
 #undef HAVE_TOWUPPER
 #undef HAVE_ISWUPPER
+#undef HAVE_TZSET
 #undef HAVE_UNSETENV
 #undef HAVE_USLEEP
 #undef HAVE_UTIME
diff --git a/src/configure.ac b/src/configure.ac
index dbf4f42b8..f7a71d079 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -3742,7 +3742,7 @@ AC_CHECK_FUNCS(fchdir fchown fchmod fsync getcwd 
getpseudotty \
        memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
        getpgid setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
        sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \
-       strnicmp strpbrk strtol tgetent towlower towupper iswupper \
+       strnicmp strpbrk strtol tgetent towlower towupper iswupper tzset \
        usleep utime utimes mblen ftruncate unsetenv posix_openpt)
 AC_FUNC_SELECT_ARGTYPES
 AC_FUNC_FSEEKO
diff --git a/src/datetime.c b/src/datetime.c
new file mode 100644
index 000000000..445e844d4
--- /dev/null
+++ b/src/datetime.c
@@ -0,0 +1,74 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved   by Bram Moolenaar
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * datetime.c: functions for manipulating dates and time
+ */
+
+#include "vim.h"
+
+#include "datetime.h"  // includes time.h for localtime()
+
+#define DATETIME_TZ_CACHEL 32
+
+static char    tz_cache[DATETIME_TZ_CACHEL];
+
+/*
+ * Maintain a cache of the current timezone name as retrieved from TZ, or an
+ * empty string where unset, up to DATETIME_TZ_CACHEL-1 octets long.  Each time
+ * this function is called, if the timezone has changed since the last time,
+ * apply the tzset(3) function to update the external timezone variables (if
+ * supported), and update the cached value.  If tzset(3) isn't available on
+ * this system, this function does nothing.
+ */
+    static void
+vim_tzset(
+    void)      // no arguments
+{
+#ifdef HAVE_TZSET
+    char       *tz;    // timezone retrieved from environment TZ
+
+    tz = mch_getenv((char_u *)"TZ");
+    if (tz == NULL)
+       tz = "";
+    if (strncmp(tz, tz_cache, DATETIME_TZ_CACHEL) != 0)
+    {
+       if (p_verbose > 0)
+       {
+           verbose_enter();
+           smsg(
+               _("Updating cached timezone TZ from environment"));
+           verbose_leave();
+       }
+       tzset();
+       vim_strncpy(tz_cache, tz, DATETIME_TZ_CACHEL - 1);
+    }
+#endif // HAVE_TZSET
+    return;
+}
+
+/*
+ * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
+ * latter version preferred if available for reentrancy.  If we use
+ * localtime_r(3), include a call to vim_tzset() first, as the POSIX standard
+ * doesn't require localtime_r(3) implementations to do that as it does with
+ * localtime(3).
+ */
+    struct tm *
+vim_localtime(
+    const      time_t *timep,  // timestamp for local representation
+    struct     tm *result)             // pointer to caller's buffer for return
+{
+#ifdef HAVE_LOCALTIME_R
+    vim_tzset();
+    return localtime_r(timep, result);
+#else
+    return localtime(timep);
+#endif // HAVE_LOCALTIME_R
+}
diff --git a/src/datetime.h b/src/datetime.h
new file mode 100644
index 000000000..180466ea5
--- /dev/null
+++ b/src/datetime.h
@@ -0,0 +1,16 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved   by Bram Moolenaar
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * datetime.h: headers for functions for manipulating dates and time
+ */
+
+#include <time.h>      /* for `struct tm` and time_t */
+
+struct tm *vim_localtime(const time_t *timep, struct tm *result);
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 0ef76095f..eec33a550 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -13182,9 +13182,7 @@ f_str2nr(typval_T *argvars, typval_T *rettv)
 f_strftime(typval_T *argvars, typval_T *rettv)
 {
     char_u     result_buf[256];
-# ifdef HAVE_LOCALTIME_R
     struct tm  tmval;
-# endif
     struct tm  *curtime;
     time_t     seconds;
     char_u     *p;
@@ -13196,11 +13194,7 @@ f_strftime(typval_T *argvars, typval_T *rettv)
        seconds = time(NULL);
     else
        seconds = (time_t)tv_get_number(&argvars[1]);
-# ifdef HAVE_LOCALTIME_R
-    curtime = localtime_r(&seconds, &tmval);
-# else
-    curtime = localtime(&seconds);
-# endif
+    curtime = vim_localtime(&seconds, &tmval);
     /* MSVC returns NULL for an invalid value of seconds. */
     if (curtime == NULL)
        rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
diff --git a/src/memline.c b/src/memline.c
index e7ae6dfb5..8692d0b47 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -2093,16 +2093,10 @@ get_ctime(time_t thetime, int add_newline)
 {
     static char buf[50];
 #ifdef HAVE_STRFTIME
-# ifdef HAVE_LOCALTIME_R
     struct tm  tmval;
-# endif
     struct tm  *curtime;
 
-# ifdef HAVE_LOCALTIME_R
-    curtime = localtime_r(&thetime, &tmval);
-# else
-    curtime = localtime(&thetime);
-# endif
+    curtime = vim_localtime(&thetime, &tmval);
     /* MSVC returns NULL for an invalid value of seconds. */
     if (curtime == NULL)
        vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);
diff --git a/src/proto/datetime.pro b/src/proto/datetime.pro
new file mode 100644
index 000000000..74ac953fc
--- /dev/null
+++ b/src/proto/datetime.pro
@@ -0,0 +1,3 @@
+/* datetime.c */
+struct tm *vim_localtime(const time_t *timep, struct tm *result);
+/* vim: set ft=c : */
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index a2e4da6c7..f71717f73 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -187,6 +187,30 @@ func Test_strftime()
 
   call assert_fails('call strftime([])', 'E730:')
   call assert_fails('call strftime("%Y", [])', 'E745:')
+
+  " Check that the time changes after we change the timezone
+  " Save previous timezone value, if any
+  if exists('$TZ')
+    let tz = $TZ
+  endif
+
+  " Force EST and then UTC, save the current hour (24-hour clock) for each
+  let $TZ = 'EST' | let est = strftime('%H')
+  let $TZ = 'UTC' | let utc = strftime('%H')
+
+  " Those hours should be two bytes long, and should not be the same; if they
+  " are, a tzset(3) call may have failed somewhere
+  call assert_equal(strlen(est), 2)
+  call assert_equal(strlen(utc), 2)
+  call assert_notequal(est, utc)
+
+  " If we cached a timezone value, put it back, otherwise clear it
+  if exists('tz')
+    let $TZ = tz
+  else
+    unlet $TZ
+  endif
+
 endfunc
 
 func Test_resolve_unix()
diff --git a/src/undo.c b/src/undo.c
index dd4667001..4a4a33cc1 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -3111,18 +3111,12 @@ ex_undolist(exarg_T *eap UNUSED)
 u_add_time(char_u *buf, size_t buflen, time_t tt)
 {
 #ifdef HAVE_STRFTIME
-# ifdef HAVE_LOCALTIME_R
     struct tm  tmval;
-# endif
     struct tm  *curtime;
 
     if (vim_time() - tt >= 100)
     {
-# ifdef HAVE_LOCALTIME_R
-       curtime = localtime_r(&tt, &tmval);
-# else
-       curtime = localtime(&tt);
-# endif
+       curtime = vim_localtime(&tt, &tmval);
        if (vim_time() - tt < (60L * 60L * 12L))
            /* within 12 hours */
            (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
diff --git a/src/vim.h b/src/vim.h
index d6bc6c371..c4bbe58f8 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -2087,6 +2087,7 @@ typedef enum {
 
 #include "ex_cmds.h"       /* Ex command defines */
 #include "spell.h"         /* spell checking stuff */
+#include "datetime.h"      /* date and time stuff */
 
 #include "proto.h"         /* function prototypes */
 
-- 
2.22.0

Raspunde prin e-mail lui