aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Edmund Lazo <jan.lazo@mail.utoronto.ca>2020-03-29 11:59:22 -0400
committerJan Edmund Lazo <jan.lazo@mail.utoronto.ca>2020-03-29 13:17:03 -0400
commit10c5434f9c1219d480fd07e711838e22dc912bba (patch)
tree13e7f17f37869cf2c9909d651bb901c5430e7c9e
parent573671b1fbcbc43b622391f50f4df30594f14751 (diff)
downloadrneovim-10c5434f9c1219d480fd07e711838e22dc912bba.tar.gz
rneovim-10c5434f9c1219d480fd07e711838e22dc912bba.tar.bz2
rneovim-10c5434f9c1219d480fd07e711838e22dc912bba.zip
vim-patch:8.1.1567: localtime_r() does not respond to $TZ changes
Problem: Localtime_r() does not respond to $TZ changes. Solution: If $TZ changes then call tzset(). (Tom Ryder) https://github.com/vim/vim/commit/db51730df1817fc4b6ecf5a065c69fac518ad821
-rw-r--r--src/nvim/os/time.c22
-rw-r--r--src/nvim/testdir/test_functions.vim23
2 files changed, 41 insertions, 4 deletions
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index fc04cdd55b..346e40e02e 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -2,9 +2,6 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <time.h>
#include <limits.h>
#include <uv.h>
@@ -13,7 +10,7 @@
#include "nvim/os/time.h"
#include "nvim/os/input.h"
#include "nvim/event/loop.h"
-#include "nvim/vim.h"
+#include "nvim/os/os.h"
#include "nvim/main.h"
static uv_mutex_t delay_mutex;
@@ -112,6 +109,10 @@ void os_microdelay(uint64_t us, bool ignoreinput)
uv_mutex_unlock(&delay_mutex);
}
+// Cache of the current timezone name as retrieved from TZ, or an empty string
+// where unset, up to 64 octets long including trailing null byte.
+static char tz_cache[64];
+
/// Portable version of POSIX localtime_r()
///
/// @return NULL in case of error
@@ -120,6 +121,19 @@ struct tm *os_localtime_r(const time_t *restrict clock,
{
#ifdef UNIX
// POSIX provides localtime_r() as a thread-safe version of localtime().
+ //
+ // Check to see if the environment variable TZ has changed since the last run.
+ // Call tzset(3) to update the global timezone variables if it has.
+ // POSIX standard doesn't require localtime_r() implementations to do that
+ // as it does with localtime(), and we don't want to call tzset() every time.
+ const char *tz = os_getenv("TZ");
+ if (tz == NULL) {
+ tz = "";
+ }
+ if (strncmp(tz_cache, tz, sizeof(tz_cache) - 1) != 0) {
+ tzset();
+ xstrlcpy(tz_cache, tz, sizeof(tz_cache));
+ }
return localtime_r(clock, result); // NOLINT(runtime/threadsafe_fn)
#else
// Windows version of localtime() is thread-safe.
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 7822507f86..da5edbaea1 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -186,6 +186,29 @@ 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()