[PATCH] libstdc++: Fix chrono::current_zone() for three component names [PR122567]

Jonathan Wakely jwakely@redhat.com
Fri Jan 9 17:35:17 GMT 2026


chrono::current_zone() fails if /etc/localtime is a symlink to a zone
with three components, like "America/Indiana/Indianapolis", because we
only try to find "Indianapolis" and "Indiana/Indianapolis" but neither
of those exists.

We need to try up to three components to handle all valid cases, such as
"UTC", "America/Indianapolis", and "America/Indiana/Indianapolis".

Since two components is the most common case, we could consider trying
last[-2]/last[-1] first, then if that doesn't match trying only the last
component and the last three components, but this patch doesn't do that.

libstdc++-v3/ChangeLog:

	PR libstdc++/122567
	* src/c++20/tzdb.cc (tzdb::current_zone): Loop over trailing
	components of /etc/localtime path for up to three components.
---

Tested x86_64-linux.

There's no new testcase for this because it requires root access to
change /etc/localtime. I've verified it locally.

 libstdc++-v3/src/c++20/tzdb.cc | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc
index 53441880ae6e..44ba3ea890f2 100644
--- a/libstdc++-v3/src/c++20/tzdb.cc
+++ b/libstdc++-v3/src/c++20/tzdb.cc
@@ -1896,14 +1896,24 @@ namespace std::chrono
 	auto first = path.begin(), last = path.end();
 	if (std::distance(first, last) > 2)
 	  {
-	    --last;
-	    string name = last->string();
-	    if (auto tz = do_locate_zone(this->zones, this->links, name))
-	      return tz;
-	    --last;
-	    name = last->string() + '/' + name;
-	    if (auto tz = do_locate_zone(this->zones, this->links, name))
-	      return tz;
+	    string name, part;
+	    // Check trailing components of the path against known zone names.
+	    // Valid zones can have one, two, or three components, e.g.
+	    // "UTC", "Europe/London", "America/Indiana/Indianapolis"
+	    for (int i = 0; i < 3 && last != first; ++i)
+	      {
+		--last;
+		part = last->string();
+		if (name.empty())
+		  name = std::move(part);
+		else
+		  {
+		    part += '/';
+		    name = std::move(part) + std::move(name);
+		  }
+		if (auto tz = do_locate_zone(this->zones, this->links, name))
+		  return tz;
+	      }
 	  }
       }
 #endif
-- 
2.52.0



More information about the Libstdc++ mailing list