[libcxx-commits] [libcxx] f796747 - [libc++][TZDB] Improves system time zone detection. (#127339)
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Feb 18 10:28:20 PST 2025
Author: Mark de Wever
Date: 2025-02-18T19:28:16+01:00
New Revision: f796747a17941681c8f806cab4e10570b97b5089
URL: https://github.com/llvm/llvm-project/commit/f796747a17941681c8f806cab4e10570b97b5089
DIFF: https://github.com/llvm/llvm-project/commit/f796747a17941681c8f806cab4e10570b97b5089.diff
LOG: [libc++][TZDB] Improves system time zone detection. (#127339)
On some (Linux) systems /etc/localtime is not a symlink to the time
zone, but contains a copy of the binary time zone file. In these case
there usually is a file named /etc/timezone which contains the text for
the current time zone name.
Instead of throwing when /etc/localtime does not exist or is not a
symlink use this fallback.
Fixes: #105634
---------
Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>
Added:
Modified:
libcxx/src/experimental/tzdb.cpp
Removed:
################################################################################
diff --git a/libcxx/src/experimental/tzdb.cpp b/libcxx/src/experimental/tzdb.cpp
index f38f495c2d0bb..1f18226636fd5 100644
--- a/libcxx/src/experimental/tzdb.cpp
+++ b/libcxx/src/experimental/tzdb.cpp
@@ -708,6 +708,39 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
std::__throw_runtime_error("unknown time zone");
}
#else // ifdef _WIN32
+
+[[nodiscard]] static string __current_zone_environment() {
+ if (const char* __tz = std::getenv("TZ"))
+ return __tz;
+
+ return {};
+}
+
+[[nodiscard]] static string __current_zone_etc_localtime() {
+ filesystem::path __path = "/etc/localtime";
+ if (!filesystem::exists(__path) || !filesystem::is_symlink(__path))
+ return {};
+
+ filesystem::path __tz = filesystem::read_symlink(__path);
+ // The path may be a relative path, in that case convert it to an absolute
+ // path based on the proper initial directory.
+ if (__tz.is_relative())
+ __tz = filesystem::canonical("/etc" / __tz);
+
+ return filesystem::relative(__tz, "/usr/share/zoneinfo/");
+}
+
+[[nodiscard]] static string __current_zone_etc_timezone() {
+ filesystem::path __path = "/etc/timezone";
+ if (!filesystem::exists(__path))
+ return {};
+
+ ifstream __f(__path);
+ string __name;
+ std::getline(__f, __name);
+ return __name;
+}
+
[[nodiscard]] static const time_zone* __current_zone_posix(const tzdb& tzdb) {
// On POSIX systems there are several ways to configure the time zone.
// In order of priority they are:
@@ -726,30 +759,28 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
//
// - The time zone name is the target of the symlink /etc/localtime
// relative to /usr/share/zoneinfo/
+ //
+ // - The file /etc/timezone. This text file contains the name of the time
+ // zone.
+ //
+ // On Linux systems it seems /etc/timezone is deprecated and being phased
+ // out. This file is used when /etc/localtime does not exist, or when it exists but is not a symlink. For more information and links see
+ // https://github.com/llvm/llvm-project/issues/105634
- // The algorithm is like this:
- // - If the environment variable TZ is set and points to a valid
- // record use this value.
- // - Else use the name based on the `/etc/localtime` symlink.
+ string __name = chrono::__current_zone_environment();
- if (const char* __tz = getenv("TZ"))
- if (const time_zone* __result = tzdb.__locate_zone(__tz))
+ // Ignore invalid names in the environment.
+ if (!__name.empty())
+ if (const time_zone* __result = tzdb.__locate_zone(__name))
return __result;
- filesystem::path __path = "/etc/localtime";
- if (!filesystem::exists(__path))
- std::__throw_runtime_error("tzdb: the symlink '/etc/localtime' does not exist");
-
- if (!filesystem::is_symlink(__path))
- std::__throw_runtime_error("tzdb: the path '/etc/localtime' is not a symlink");
+ __name = chrono::__current_zone_etc_localtime();
+ if (__name.empty())
+ __name = chrono::__current_zone_etc_timezone();
- filesystem::path __tz = filesystem::read_symlink(__path);
- // The path may be a relative path, in that case convert it to an absolute
- // path based on the proper initial directory.
- if (__tz.is_relative())
- __tz = filesystem::canonical("/etc" / __tz);
+ if (__name.empty())
+ std::__throw_runtime_error("tzdb: unable to determine the name of the current time zone");
- string __name = filesystem::relative(__tz, "/usr/share/zoneinfo/");
if (const time_zone* __result = tzdb.__locate_zone(__name))
return __result;
More information about the libcxx-commits
mailing list