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?

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