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

Reply via email to