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

openSUSE Build Service is sponsored by