@@ -708,6 +708,39 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
708708 std::__throw_runtime_error (" unknown time zone" );
709709}
710710#else // ifdef _WIN32
711+
712+ [[nodiscard]] static string __current_zone_environment () {
713+ if (const char * __tz = std::getenv (" TZ" ))
714+ return __tz;
715+
716+ return {};
717+ }
718+
719+ [[nodiscard]] static string __current_zone_etc_localtime () {
720+ filesystem::path __path = " /etc/localtime" ;
721+ if (!filesystem::exists (__path) || !filesystem::is_symlink (__path))
722+ return {};
723+
724+ filesystem::path __tz = filesystem::read_symlink (__path);
725+ // The path may be a relative path, in that case convert it to an absolute
726+ // path based on the proper initial directory.
727+ if (__tz.is_relative ())
728+ __tz = filesystem::canonical (" /etc" / __tz);
729+
730+ return filesystem::relative (__tz, " /usr/share/zoneinfo/" );
731+ }
732+
733+ [[nodiscard]] static string __current_zone_etc_timezone () {
734+ filesystem::path __path = " /etc/timezone" ;
735+ if (!filesystem::exists (__path))
736+ return {};
737+
738+ ifstream __f (__path);
739+ string __name;
740+ std::getline (__f, __name);
741+ return __name;
742+ }
743+
711744[[nodiscard]] static const time_zone* __current_zone_posix (const tzdb& tzdb) {
712745 // On POSIX systems there are several ways to configure the time zone.
713746 // In order of priority they are:
@@ -726,30 +759,28 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
726759 //
727760 // - The time zone name is the target of the symlink /etc/localtime
728761 // relative to /usr/share/zoneinfo/
762+ //
763+ // - The file /etc/timezone. This text file contains the name of the time
764+ // zone.
765+ //
766+ // On Linux systems it seems /etc/timezone is deprecated and being phased
767+ // 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
768+ // https://github.com/llvm/llvm-project/issues/105634
729769
730- // The algorithm is like this:
731- // - If the environment variable TZ is set and points to a valid
732- // record use this value.
733- // - Else use the name based on the `/etc/localtime` symlink.
770+ string __name = chrono::__current_zone_environment ();
734771
735- if (const char * __tz = getenv (" TZ" ))
736- if (const time_zone* __result = tzdb.__locate_zone (__tz))
772+ // Ignore invalid names in the environment.
773+ if (!__name.empty ())
774+ if (const time_zone* __result = tzdb.__locate_zone (__name))
737775 return __result;
738776
739- filesystem::path __path = " /etc/localtime" ;
740- if (!filesystem::exists (__path))
741- std::__throw_runtime_error (" tzdb: the symlink '/etc/localtime' does not exist" );
742-
743- if (!filesystem::is_symlink (__path))
744- std::__throw_runtime_error (" tzdb: the path '/etc/localtime' is not a symlink" );
777+ __name = chrono::__current_zone_etc_localtime ();
778+ if (__name.empty ())
779+ __name = chrono::__current_zone_etc_timezone ();
745780
746- filesystem::path __tz = filesystem::read_symlink (__path);
747- // The path may be a relative path, in that case convert it to an absolute
748- // path based on the proper initial directory.
749- if (__tz.is_relative ())
750- __tz = filesystem::canonical (" /etc" / __tz);
781+ if (__name.empty ())
782+ std::__throw_runtime_error (" tzdb: unable to determine the name of the current time zone" );
751783
752- string __name = filesystem::relative (__tz, " /usr/share/zoneinfo/" );
753784 if (const time_zone* __result = tzdb.__locate_zone (__name))
754785 return __result;
755786
0 commit comments