[PATCH] libstdc++: Fix chrono::current_zone() for three component names [PR122567]
Jonathan Wakely
jwakely@redhat.com
Fri Jan 9 18:32:58 GMT 2026
On Fri, 9 Jan 2026 at 18:13, Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>
>
> On Fri, Jan 9, 2026 at 6:58 PM Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>>
>>
>>
>> On Fri, Jan 9, 2026 at 6:37 PM Jonathan Wakely <jwakely@redhat.com> 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
>>>
More information about the Libstdc++
mailing list