File 1192-erts-On-windows-use-TZ-env-var-for-selecting-time-zo.patch of Package erlang
From 82cca863425d81050032f165500c551a1f4789c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lukas=20Backstr=C3=B6m?= <lukas@erlang.org>
Date: Tue, 17 Dec 2024 08:58:57 +0100
Subject: [PATCH 2/3] erts: On windows use "TZ" env var for selecting time zone
According to POSIX.1 when selecting which time zone a
system should run in, it should first look at the "TZ"
environment variable. This is what mktime and friends
do on Unix+Windows, but as Erlang has its own implementation
of mktime this was not true.
This commit reads the environment variable and from
that looks up the required information from the registry.
---
erts/emulator/sys/win32/sys_time.c | 67 +++++++++++++++++++++++++++---
erts/emulator/test/time_SUITE.erl | 38 +++++++----------
2 files changed, 78 insertions(+), 27 deletions(-)
diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c
index c8c8b6bba6..20d43d0c3f 100644
--- a/erts/emulator/sys/win32/sys_time.c
+++ b/erts/emulator/sys/win32/sys_time.c
@@ -286,9 +286,65 @@ sys_hrtime_gtc64(void)
return time;
}
-/*
- * Init
- */
+/* Struct and algorithm taken from https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-time_zone_information */
+typedef struct _REG_TZI_FORMAT
+{
+ LONG Bias;
+ LONG StandardBias;
+ LONG DaylightBias;
+ SYSTEMTIME StandardDate;
+ SYSTEMTIME DaylightDate;
+} REG_TZI_FORMAT;
+
+static int sys_init_tzinfo(void) {
+ char *tz = getenv("TZ");
+ char regKey[255];
+ HKEY tzKey;
+ DWORD res, size;
+ REG_TZI_FORMAT tzi;
+
+
+ /* If TZ is not set we fallback to GetTimeZoneInformation, just like mktime and friends. */
+ if (!tz) {
+ return GetTimeZoneInformation(&static_tzi);
+ }
+
+ snprintf(regKey, sizeof(regKey), "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\%s", tz);
+
+ if ((res = RegOpenKey(HKEY_LOCAL_MACHINE, regKey, &tzKey)) != ERROR_SUCCESS) {
+ return 0;
+ }
+
+ size = sizeof(tzi);
+ if ((res = RegGetValueW(tzKey, NULL, L"TZI", RRF_RT_REG_BINARY, NULL,
+ &tzi, &size)) != ERROR_SUCCESS) {
+ RegCloseKey(tzKey);
+ return 0;
+ }
+
+ static_tzi.Bias = tzi.Bias;
+ static_tzi.StandardBias = tzi.StandardBias;
+ static_tzi.DaylightBias = tzi.DaylightBias;
+ static_tzi.StandardDate = tzi.StandardDate;
+ static_tzi.DaylightDate = tzi.DaylightDate;
+
+ size = sizeof(static_tzi.StandardName);
+ if ((res = RegGetValueW(tzKey, NULL, L"Std", RRF_RT_REG_SZ, NULL,
+ &static_tzi.StandardName, &size)) != ERROR_SUCCESS) {
+ RegCloseKey(tzKey);
+ return 0;
+ }
+
+ size = sizeof(static_tzi.DaylightName);
+ if ((res = RegGetValueW(tzKey, NULL, L"Dlt", RRF_RT_REG_SZ, NULL,
+ &static_tzi.DaylightName, &size)) != ERROR_SUCCESS) {
+ RegCloseKey(tzKey);
+ return 0;
+ }
+
+ RegCloseKey(tzKey);
+ return 1;
+}
void
sys_init_time(ErtsSysInitTimeResult *init_resp)
@@ -407,8 +463,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
init_resp->os_system_time_info.resolution = 100;
init_resp->os_system_time_info.locked_use = 0;
- if(GetTimeZoneInformation(&static_tzi)) {
- have_static_tzi = 1;
+ have_static_tzi = sys_init_tzinfo();
+
+ if (have_static_tzi) {
sys_daylight = static_tzi.StandardDate.wMonth != 0 &&
static_tzi.DaylightDate.wMonth != 0;
}
diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl
index ce3e796da5..636db370da 100644
--- a/erts/emulator/test/time_SUITE.erl
+++ b/erts/emulator/test/time_SUITE.erl
@@ -107,31 +107,23 @@ end_per_group(_GroupName, Config) ->
%% Test that DST = true on timezones without DST is ignored
local_to_univ_utc(Config) when is_list(Config) ->
- case os:type() of
- {unix,_} ->
- %% TZ variable has a meaning
- {ok, Node} =
- test_server:start_node(local_univ_utc,peer,
- [{args, "-env TZ UTC"}]),
- {{2008,8,1},{0,0,0}} =
- rpc:call(Node,
- erlang,localtime_to_universaltime,
- [{{2008, 8, 1}, {0, 0, 0}},
- false]),
- {{2008,8,1},{0,0,0}} =
- rpc:call(Node,
- erlang,localtime_to_universaltime,
- [{{2008, 8, 1}, {0, 0, 0}},
- true]),
- [{{2008,8,1},{0,0,0}}] =
- rpc:call(Node,
- calendar,local_time_to_universal_time_dst,
- [{{2008, 8, 1}, {0, 0, 0}}]),
- test_server:stop_node(Node),
- ok;
- _ ->
- {skip,"Only valid on Unix"}
- end.
+ {ok, Node} = test_server:start_node(local_univ_utc,peer, [{args, "-env TZ UTC"}]),
+ {{2008,8,1},{0,0,0}} =
+ rpc:call(Node,
+ erlang,localtime_to_universaltime,
+ [{{2008, 8, 1}, {0, 0, 0}},
+ false]),
+ {{2008,8,1},{0,0,0}} =
+ rpc:call(Node,
+ erlang,localtime_to_universaltime,
+ [{{2008, 8, 1}, {0, 0, 0}},
+ true]),
+ [{{2008,8,1},{0,0,0}}] =
+ rpc:call(Node,
+ calendar,local_time_to_universal_time_dst,
+ [{{2008, 8, 1}, {0, 0, 0}}]),
+ test_server:stop_node(Node),
+ ok.
%% Tests conversion from universal to local time.
--
2.43.0