[RFC] libstdc++: chrono::current_zone() should always respect $TZ
Jonathan Wakely
jwakely.gcc@gmail.com
Mon May 8 08:06:13 GMT 2023
On Mon, 8 May 2023, 08:41 Jonathan Wakely, <jwakely.gcc@gmail.com> wrote:
>
>
> On Sun, 7 May 2023, 22:55 James Morris via Libstdc++, <
> libstdc++@gcc.gnu.org> wrote:
>
>> Hello,
>>
>> I was playing around with GCC 13 and upgrading some old C++ code to
>> C++20. I had a small function for getting the current time based on
>> the <ctime> functions and tried to convert it to use the new <chrono>
>> functions. I was quite surprised that when using
>> chrono::current_zone(), my program stopped responding to the TZ
>> environment variable.
>>
>> I'd like to propose that chrono::current_zone() always pays attention
>> to $TZ so as not to surprise users moving from <ctime>. tzdb.cc
>> already has code for this gated by an #ifdef, so maybe all that needs
>> to be done is to make that code available to all platforms.
>>
>
> No, this is not a good idea. Libstdc++ cannot inspect the environment
> safely because another thread could be changing it concurrently, which
> would lead to undefined behaviour. The commented out code was an
>
Sorry, I mean #ifdef'd code, not commented out.
In any case, that code is a last resort because AIX leaves us no other
option except for parsing /etc/environment to find TZ (but I don't know if
that's reliable/correct either).
attempt to support <chrono> on AIX which is unconventional and has no
> /etc/localtime symlink.
>
> In any case, the C++ standard requires that current_zone() refers to the
> computer's zone, not just the current process' TZ setting:
>
> "A pointer to the time zone which the computer has set as its local time
> zone."
>
> <chrono> is not <ctime>. The chrono lib is not restricted to only working
> with a global time zone defined in the standard library, but instead
> everything works equally well with any chrono::time_zone object, whether
> that refers to the system zone or not. If you want to use a per-process
> zone specified by $TZ then you can easily do so, using something like:
>
> const chrono::time_zone* tz;
> if (auto env = getenv("TZ"))
> tz = chrono::locate_zone(env);
> if (!tz)
> tz = chrono::current_zone();
>
> This makes it your problem if you modify the environment in parallel. You
> can choose to do this in main() before starting other threads, but that's
> not something which libstdc++ can control, as current_zone() must work from
> anywhere in the program.
>
>
>> Example of my code with <ctime>:
>>
>> ```
>> #include <ctime>
>> #include <iostream>
>>
>> int main() {
>> std::time_t epoch_time = std::time(nullptr);
>> std::tm* local_time = std::localtime(&epoch_time);
>>
>> char time_string[] = "00:00:00 UTC";
>> std::strftime(time_string, sizeof "00:00:00 UTC", "%T %Z",
>> local_time);
>>
>> std::cout << time_string << '\n';
>> }
>> ```
>>
>> Example of what I tried to do with <chrono>:
>>
>> ```
>> #include <chrono>
>> #include <format>
>> #include <iostream>
>>
>> namespace chrono = std::chrono;
>>
>> int main() {
>> auto zt = chrono::zoned_time(chrono::current_zone(),
>> chrono::system_clock::now());
>> std::cout << std::format("{:%T %Z}", zt) << '\n';
>> }
>> ```
>>
>> Diff of proposed changes:
>>
>> ```
>> diff --git a/libstdc++-v3/src/c++20/tzdb.cc
>> b/libstdc++-v3/src/c++20/tzdb.cc
>> index a43b4f33eba..c16913dab67 100644
>> --- a/libstdc++-v3/src/c++20/tzdb.cc
>> +++ b/libstdc++-v3/src/c++20/tzdb.cc
>> @@ -1632,6 +1632,20 @@ namespace std::chrono
>> {
>> // TODO cache this function's result?
>>
>> + // AIX stores current zone in $TZ in /etc/environment but the value
>> + // is typically a POSIX time zone name, not IANA zone.
>> + // https://developer.ibm.com/articles/au-aix-posix/
>> + //
>> https://www.ibm.com/support/pages/managing-time-zone-variable-posix
>> + //
>> + // Other POSIX systems also allow the user to override the
>> + // system timezone by setting $TZ.
>> + if (const char* env = std::getenv("TZ"))
>> + {
>> + // This will fail unless TZ contains an IANA time zone name.
>> + if (auto tz = do_locate_zone(this->zones, this->links, env))
>> + return tz;
>> + }
>> +
>> #ifndef _AIX
>> error_code ec;
>> // This should be a symlink to e.g. /usr/share/zoneinfo/Europe/London
>> @@ -1685,17 +1699,6 @@ namespace std::chrono
>> return tz;
>> }
>> }
>> -#else
>> - // AIX stores current zone in $TZ in /etc/environment but the value
>> - // is typically a POSIX time zone name, not IANA zone.
>> - // https://developer.ibm.com/articles/au-aix-posix/
>> - //
>> https://www.ibm.com/support/pages/managing-time-zone-variable-posix
>> - if (const char* env = std::getenv("TZ"))
>> - {
>> - // This will fail unless TZ contains an IANA time zone name.
>> - if (auto tz = do_locate_zone(this->zones, this->links, env))
>> - return tz;
>> - }
>> #endif
>>
>> // Default to UTC.
>> ```
>>
>> Thanks,
>> James
>>
>
More information about the Libstdc++
mailing list