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? > 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 >> >>
