On Fri, 9 Jan 2026 at 18:13, Tomasz Kaminski <[email protected]> wrote: > > > > On Fri, Jan 9, 2026 at 6:58 PM Tomasz Kaminski <[email protected]> wrote: >> >> >> >> On Fri, Jan 9, 2026 at 6:37 PM Jonathan Wakely <[email protected]> wrote: >>> >>> 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) >> >> Is there any real benefit of hardcoding 3 components here, instead of using >> while (last != first), so we would handle any longer names?
It will slow down the unlikely case, where the symlink refers to a zone that we don't recognize as a valid name, but that's probably not a major concern. The docs say that most zones should have a name of the form AREA/LOCATION so more than two components is already rare: https://data.iana.org/time-zones/theory.html#naming Four or more components isn't actually forbidden, but it seems very unlikely. > > If we have more than 4 components in future, then such a new timezone database > can be downloaded by the older version of the library. And we will checking > only more > than tree components, only if the current zone is not something that we could > match. >> >> >>> >>> + { >>> + --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 >>>
