comphelper/source/misc/lok.cxx |   11 +++++------
 include/comphelper/lok.hxx     |    2 +-
 include/osl/time.h             |   12 ++++++++++++
 sal/Library_sal.mk             |    1 +
 sal/osl/all/time.cxx           |   40 ++++++++++++++++++++++++++++++++++++++++
 sal/osl/unx/time.cxx           |    1 +
 sal/qa/osl/time/osl_Time.cxx   |    8 ++++----
 sal/util/sal.map               |    6 ++++++
 8 files changed, 70 insertions(+), 11 deletions(-)

New commits:
commit 82de06cb8c26bafa5a275315c77f6cd677e1e2f3
Author:     Michael Meeks <[email protected]>
AuthorDate: Fri Feb 20 02:01:05 2026 +0000
Commit:     Noel Grandin <[email protected]>
CommitDate: Sat Feb 21 13:02:30 2026 +0100

    sal: move tzset and environment variable setting logic into sal.
    
    Add osl_setTimezone and osl_resetTimezone() and export them as a
    sensibly wrapped way to change the timezone at runtime, and use them.
    
    Update the sal time unit tests to use osl_setTimezone/osl_resetTimezone.
    
    Change-Id: I840ae6c3692853137e769dced594a0e88cef16b9
    Signed-off-by: Michael Meeks <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199828
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/comphelper/source/misc/lok.cxx b/comphelper/source/misc/lok.cxx
index 7e9373fc44cc..406df02c8ff6 100644
--- a/comphelper/source/misc/lok.cxx
+++ b/comphelper/source/misc/lok.cxx
@@ -12,6 +12,7 @@
 #include <com/sun/star/awt/Rectangle.hpp>
 
 #include <osl/process.h>
+#include <osl/time.h>
 #include <i18nlangtag/languagetag.hxx>
 #include <sal/log.hxx>
 #ifdef _WIN32
@@ -312,22 +313,20 @@ bool isAllowlistedLanguage(const OUString& lang)
 #endif
 }
 
-void setTimezone(bool isSet, const OUString& rTimezone)
+void setTimezone(bool isSet, std::u16string_view rTimezone)
 {
     if (isSet)
     {
         // Set the given timezone, even if empty.
-        osl_setEnvironment(u"TZ"_ustr.pData, rTimezone.pData);
+        OString aTZ = OUStringToOString(rTimezone, RTL_TEXTENCODING_UTF8);
+        osl_setTimezone(aTZ.getStr());
     }
     else
     {
         // Unset and empty aren't the same.
         // When unset, it means default to the system configured timezone.
-        osl_clearEnvironment(u"TZ"_ustr.pData);
+        osl_resetTimezone();
     }
-
-    // Update the timezone data.
-    ::tzset();
 }
 
 static void (*pStatusIndicatorCallback)(void *data, 
statusIndicatorCallbackType type, int percent, const char* pText)(nullptr);
diff --git a/include/comphelper/lok.hxx b/include/comphelper/lok.hxx
index ebdb8439ba0e..906f49f30ccf 100644
--- a/include/comphelper/lok.hxx
+++ b/include/comphelper/lok.hxx
@@ -134,7 +134,7 @@ COMPHELPER_DLLPUBLIC const LanguageTag& getLanguageTag();
 COMPHELPER_DLLPUBLIC bool isAllowlistedLanguage(const OUString& lang);
 
 /// Update the current LOK's timezone.
-COMPHELPER_DLLPUBLIC void setTimezone(bool isSet, const OUString& rTimezone);
+COMPHELPER_DLLPUBLIC void setTimezone(bool isSet, std::u16string_view 
rTimezone);
 
 // Status indicator handling. Even if in theory there could be several status 
indicators active at
 // the same time, in practice there is only one at a time, so we don't handle 
any identification of
diff --git a/include/osl/time.h b/include/osl/time.h
index f2f5b7a4f8ed..649180c7a676 100644
--- a/include/osl/time.h
+++ b/include/osl/time.h
@@ -175,6 +175,18 @@ SAL_DLLPUBLIC sal_Bool SAL_CALL 
osl_getLocalTimeFromSystemTime(
 SAL_DLLPUBLIC sal_Bool SAL_CALL osl_getSystemTimeFromLocalTime(
         const TimeValue* pLocalTimeVal, TimeValue* pSystemTimeVal );
 
+/** Set the timezone used by osl_getLocalTimeFromSystemTime and
+    osl_getSystemTimeFromLocalTime to the given IANA timezone ID
+    (e.g. "America/New_York"). Also sets the $TZ environment variable.
+
+    @param[in] pTimezone IANA timezone ID (null-terminated ASCII string).
+*/
+SAL_DLLPUBLIC void SAL_CALL osl_setTimezone(const char* pTimezone);
+
+/** Reset the timezone to the system default.
+    Unsets the $TZ environment variable.
+*/
+SAL_DLLPUBLIC void SAL_CALL osl_resetTimezone(void);
 
 /** Get the value of the global timer
     @return current timer value in milliseconds
diff --git a/sal/Library_sal.mk b/sal/Library_sal.mk
index c85c58ecb232..d68a4f95065c 100644
--- a/sal/Library_sal.mk
+++ b/sal/Library_sal.mk
@@ -97,6 +97,7 @@ $(eval $(call gb_Library_add_exception_objects,sal,\
        sal/osl/all/mutexshared \
        sal/osl/all/signalshared  \
        sal/osl/all/threadshared \
+       sal/osl/all/time \
        sal/osl/all/utility \
        sal/rtl/alloc_arena \
        sal/rtl/alloc_cache \
diff --git a/sal/osl/all/time.cxx b/sal/osl/all/time.cxx
new file mode 100644
index 000000000000..51fdc9366ff4
--- /dev/null
+++ b/sal/osl/all/time.cxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <cstdint>
+#include <cstdlib>
+#include <osl/time.h>
+#include <time.h>
+#ifdef WIN32
+#include <stdlib.h>
+#endif
+
+// FIXME: in-time we should move all timezone related code using ICU here.
+void SAL_CALL osl_setTimezone(const char* pTimezone)
+{
+    if (pTimezone)
+#ifdef WIN32
+        _putenv_s("TZ", pTimezone);
+#else
+        setenv("TZ", pTimezone, 1);
+#endif
+}
+
+void SAL_CALL osl_resetTimezone()
+{
+#ifdef WIN32
+    _putenv_s("TZ", "");
+#else
+    unsetenv("TZ");
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/osl/unx/time.cxx b/sal/osl/unx/time.cxx
index e4bac084da25..eeb25efffea2 100644
--- a/sal/osl/unx/time.cxx
+++ b/sal/osl/unx/time.cxx
@@ -23,6 +23,7 @@
 #include "tz.hxx"
 
 #include <cstdint>
+#include <cstdlib>
 #include <osl/time.h>
 #include <time.h>
 #include <unistd.h>
diff --git a/sal/qa/osl/time/osl_Time.cxx b/sal/qa/osl/time/osl_Time.cxx
index 380df5f7ecab..a95d5e471769 100644
--- a/sal/qa/osl/time/osl_Time.cxx
+++ b/sal/qa/osl/time/osl_Time.cxx
@@ -19,7 +19,7 @@
 
 namespace
 {
-/// RAII helper to set $TZ and restore it on destruction.
+/// RAII helper to set timezone via osl_setTimezone and restore on destruction.
 class TZGuard
 {
     std::string m_oldTZ;
@@ -32,14 +32,14 @@ public:
         m_hadTZ = (old != nullptr);
         if (m_hadTZ)
             m_oldTZ = old;
-        setenv("TZ", tz, 1);
+        osl_setTimezone(tz);
     }
     ~TZGuard()
     {
         if (m_hadTZ)
-            setenv("TZ", m_oldTZ.c_str(), 1);
+            osl_setTimezone(m_oldTZ.c_str());
         else
-            unsetenv("TZ");
+            osl_resetTimezone();
     }
 };
 
diff --git a/sal/util/sal.map b/sal/util/sal.map
index c5c3e4d55641..b7d29a490481 100644
--- a/sal/util/sal.map
+++ b/sal/util/sal.map
@@ -705,6 +705,12 @@ LIBO_UDK_6.2 { # symbols available in >= LibO 6.2
         osl_replaceFile;
 } LIBO_UDK_5.3;
 
+LIBO_UDK_26.08 { # symbols available in >= LibO 26.8
+    global:
+        osl_setTimezone;
+        osl_resetTimezone;
+} LIBO_UDK_6.2;
+
 PRIVATE_1.0 {
     global:
         osl_detail_ObjectRegistry_storeAddresses;

Reply via email to