public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux
@ 2024-04-08 19:01 hristo at venev dot name
  2024-04-08 19:27 ` [Bug libstdc++/114645] " redi at gcc dot gnu.org
                   ` (22 more replies)
  0 siblings, 23 replies; 24+ messages in thread
From: hristo at venev dot name @ 2024-04-08 19:01 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

            Bug ID: 114645
           Summary: std::chrono::current_zone ignores $TZ on Linux
           Product: gcc
           Version: 13.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: hristo at venev dot name
  Target Milestone: ---

On all platforms, glibc first checks $TZ, and only defaults to `/etc/localtime`
if it isn't set. Empty $TZ means UTC. One starting `:` is removed.

glibc interprets $TZ as a path, which is resolved relative to
${TZDIR:-default_tzdir}.

(if __libc_enable_secure is set, some checks are made to $TZ to prevent reading
of arbitrary files. In particular, it must not contain "../", and if absolute,
must either be "/etc/localtime" or must start with the default $TZDIR)

Some more details:

https://sourceware.org/git/?p=glibc.git;a=blob;f=time/tzset.c;hb=ae7468a7b0bcf22e9cd5fcae42bb9e4f65de83ee#l365

https://sourceware.org/git/?p=glibc.git;a=blob;f=time/tzfile.c;hb=ae7468a7b0bcf22e9cd5fcae42bb9e4f65de83ee#l105

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
@ 2024-04-08 19:27 ` redi at gcc dot gnu.org
  2024-04-08 20:23 ` hristo at venev dot name
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-08 19:27 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Ignoring $TZ is a feature, not a bug.

See https://gcc.gnu.org/pipermail/libstdc++/2023-May/055928.html and the
replies, including https://gcc.gnu.org/pipermail/libstdc++/2023-May/055933.html

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
  2024-04-08 19:27 ` [Bug libstdc++/114645] " redi at gcc dot gnu.org
@ 2024-04-08 20:23 ` hristo at venev dot name
  2024-04-08 20:25 ` redi at gcc dot gnu.org
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: hristo at venev dot name @ 2024-04-08 20:23 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #2 from Hristo Venev <hristo at venev dot name> ---
That makes current_zone() quite a bit completely useless and means that
practically every use of current_zone() is most likely a bug.

Is there some way to get the timezone libc would consider local?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
  2024-04-08 19:27 ` [Bug libstdc++/114645] " redi at gcc dot gnu.org
  2024-04-08 20:23 ` hristo at venev dot name
@ 2024-04-08 20:25 ` redi at gcc dot gnu.org
  2024-04-08 20:46 ` hristo at venev dot name
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-08 20:25 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
What does "quite a bit completely useless" mean? current_zone() tells you what
/etc/localtime is set to. So it's as useless as /etc/localtime, no more and no
less.

Did you read the messages I linked to?

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (2 preceding siblings ...)
  2024-04-08 20:25 ` redi at gcc dot gnu.org
@ 2024-04-08 20:46 ` hristo at venev dot name
  2024-04-08 20:48 ` redi at gcc dot gnu.org
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: hristo at venev dot name @ 2024-04-08 20:46 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #4 from Hristo Venev <hristo at venev dot name> ---
> What does "quite a bit completely useless" mean? current_zone() tells you what /etc/localtime is set to. So it's as useless as /etc/localtime, no more and no less.

What I mean is that in its current state current_zone() is a partial (and
incorrect) reimplementation of the logic used by various libcs to determine the
local time zone. By not being an accurate enough implementation it is useless.

Given that this partial implementation is correct in some but not all cases, it
is possible that application bugs (e.g. considering that current_zone() is
equivalent to libc local time) would go unnoticed, so any use of current_zone()
is most likely a bug.

In addition to glibc and musl, various other libraries for working with time
zones in other languages honor $TZ, for example python's `dateutil` and rust's
`chrono`.

Therefore current_zone() as currently implemented is worse than useless -- it
is a footgun.

> Did you read the messages I linked to?

Yes. Here are my answers to the points raised in the messages:

> 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 attempt to
support <chrono> on AIX which is unconventional and has no /etc/localtime
symlink.

These are just excuses.

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

The people who wrote the standard probably did not consider how various
platforms handle default time zones this at all.

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

This is unrelated to the issue. Having current_zone() return the time zone the
user actually wants to use wouldn't magically take away the ability to use
other time zones. Having to reimplement libc logic in every application is not
great.

> In general, yes, but not here. That would be a glibc-specific feature, so
not portable to other targets libstdc++ supports. And in any case, I don't
think we want to depend on $TZ. That's not the intended design of the
std::chrono API.

Interesting point. Is that related to the C++ standard text mentioned in the
other message?

> Yes, and that's a flaw of <time.h>, but not a problem with <chrono>.

I don't understand why you consider the ability to override the default time
zone using an environment variable to be a flaw.

> A C++ program can use **any number** of different time zones.

Again, having sane default behavior from current_zone() wouldn't magically
prevent other time zones from being used.

> There is no
> preference given in the API to any particular time zone, unlike the libc
> <time.h> which depends on global state for "the time zone" (singular). The
> only time zone that has special treatment in the C++ API is UTC, which is
> the default time zone used by std::chrono::zoned_time<Dur> iff you don't
> construct it with a pointer to a specific time zone. But even that can be
> changed via chrono::zoned_traits.

There **is** a special preference given to the time zone returned by
current_zone() -- it is the time zone returned by current_zone(), and most
applications using the C++20 time zone library would consider it to be the
default "local" time zone.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (3 preceding siblings ...)
  2024-04-08 20:46 ` hristo at venev dot name
@ 2024-04-08 20:48 ` redi at gcc dot gnu.org
  2024-04-08 20:51 ` redi at gcc dot gnu.org
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-08 20:48 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> ---
The libc time zone doesn't necessarily correspond to anything in the IANA
database anyway. If you use a POSIX time zone definition like TZ="abc4abd" then
libc will use that to generate a custom time zone and use that for localtime,
ctime etc.

That's not compatible with the std::chrono model, which uses the IANA zones. So
"the time zone libc would consider local" might not be a real time zone anyway.

If you want to interpret $TZ then you can write code to do so, and convert that
into a name that std::chrono::locale_zone understands. So if TZ is an IANA
name, use it directly, otherwise extract the offset part and then use something
like "Etc/GMT-8".

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (4 preceding siblings ...)
  2024-04-08 20:48 ` redi at gcc dot gnu.org
@ 2024-04-08 20:51 ` redi at gcc dot gnu.org
  2024-04-08 20:56 ` hristo at venev dot name
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-08 20:51 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |WONTFIX
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Hristo Venev from comment #4)
> Therefore current_zone() as currently implemented is worse than useless --
> it is a footgun.

So don't use it then.


> The people who wrote the standard probably did not consider how various
> platforms handle default time zones this at all.

That's a pretty bug assumption, and wrong.


> I don't understand why you consider the ability to override the default time
> zone using an environment variable to be a flaw.

For one, the environment is mutable and not threadsafe.


Anyway, this isn't going to change just because you don't like it.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (5 preceding siblings ...)
  2024-04-08 20:51 ` redi at gcc dot gnu.org
@ 2024-04-08 20:56 ` hristo at venev dot name
  2024-04-09  9:19 ` redi at gcc dot gnu.org
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: hristo at venev dot name @ 2024-04-08 20:56 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #7 from Hristo Venev <hristo at venev dot name> ---
I was actually trying to fix a bug in an existing application that I didn't
write that is using std::chrono::current_zone() under the assumption that it
returns some good approximation of what should be considered the "local" time
zone. I guess I need to open a bug with the application.

Still, as I said previously, the other time zone libraries I checked attempt to
handle $TZ.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (6 preceding siblings ...)
  2024-04-08 20:56 ` hristo at venev dot name
@ 2024-04-09  9:19 ` redi at gcc dot gnu.org
  2024-04-09  9:41 ` hristo at venev dot name
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-09  9:19 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Yes, if an application assumes that chrono::current_zone matches $TZ, that's a
bug in the application. None of libstdc++, LLVM libc++, MSVC STL or the
date/tz.h reference implementation uses $TZ for chrono::current_zone, and I
don't see how we could do so without breaking the guarantee that
locate_zone(current_zone()->name()) works. The lifetime and ownership of the
pointer returned by current_zone would also be unclear if it didn't return one
of the IANA zones owned by a tzdb object.

The C++ <chrono> library is extensible outside of namespace std, for example:

    https://github.com/HowardHinnant/date/blob/master/include/date/ptz.h

(that uses the types and constants from the date namespace defined in date/tz.h
but that can be replaced by namespace date { using namespace std::chrono; })

We could provide something similar as an extension, but it wouldn't be used
automatically by chrono::current_zone, because POSIX time zones (as used by
libc) are not IANA zones.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (7 preceding siblings ...)
  2024-04-09  9:19 ` redi at gcc dot gnu.org
@ 2024-04-09  9:41 ` hristo at venev dot name
  2024-04-09  9:46 ` xry111 at gcc dot gnu.org
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: hristo at venev dot name @ 2024-04-09  9:41 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #9 from Hristo Venev <hristo at venev dot name> ---
I stumbled upon this comment in the library you linked:

https://github.com/HowardHinnant/date/blob/0e65940a7fbc4ed617a1ee111a60311eccbead9a/include/date/tz.h#L35

That comment is wrong in its explanation of the mechanism used to determine the
local time zone on Linux. However, it clearly shows that the intent is to match
the platform's "local time" as closely as reasonably possible.

The implementation also has some comments:

https://github.com/HowardHinnant/date/blob/0e65940a7fbc4ed617a1ee111a60311eccbead9a/src/tz.cpp#L3936

The intent seems to be clear -- apply a lot of heuristics to try to match what
libc would do as closely as possible.

Even on Linux there are no guarantees whatsoever that it is possible to extract
a IANA time zone from /etc/localtime. In fact, the problem is exactly identical
to that with $TZ, if not worse -- $TZ is normally an IANA time zone name,
whereas /etc/localtime is a symlink (but sometimes a hardlink or a copy) of a
file in some OS-specific directory  (sometimes, but not always,
/usr/share/zoneinfo) where the name of the file relative to the base directory
is a IANA time zone name.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (8 preceding siblings ...)
  2024-04-09  9:41 ` hristo at venev dot name
@ 2024-04-09  9:46 ` xry111 at gcc dot gnu.org
  2024-04-09  9:49 ` hristo at venev dot name
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: xry111 at gcc dot gnu.org @ 2024-04-09  9:46 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #10 from Xi Ruoyao <xry111 at gcc dot gnu.org> ---
> rust's `chrono`

Note that this is really a bad example because of CVE-2020-26235.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (9 preceding siblings ...)
  2024-04-09  9:46 ` xry111 at gcc dot gnu.org
@ 2024-04-09  9:49 ` hristo at venev dot name
  2024-04-09 16:40 ` redi at gcc dot gnu.org
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: hristo at venev dot name @ 2024-04-09  9:49 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #11 from Hristo Venev <hristo at venev dot name> ---
I never said that reading $TZ is easy, just that not doing it is (in my
opinion) wrong.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (10 preceding siblings ...)
  2024-04-09  9:49 ` hristo at venev dot name
@ 2024-04-09 16:40 ` redi at gcc dot gnu.org
  2024-04-09 17:19 ` hristo at venev dot name
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-09 16:40 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #12 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Hristo Venev from comment #9)
> I stumbled upon this comment in the library you linked:
> 
> https://github.com/HowardHinnant/date/blob/
> 0e65940a7fbc4ed617a1ee111a60311eccbead9a/include/date/tz.h#L35
> 
> That comment is wrong in its explanation of the mechanism used to determine
> the local time zone on Linux. However, it clearly shows that the intent is
> to match the platform's "local time" as closely as reasonably possible.

The intent is for current_zone() to be "the time zone which the computer has
set as its local time zone", not the time zone that _the process_ has set via
TZ. That's /etc/localtime on GNU/Linux and many unixes. Which is what the
comment says.

$TZ allows you to override it per-process (and even change it during the
lifetime of a process by using setenv and tzset). We don't support that for
current_zone().

> The implementation also has some comments:
> 
> https://github.com/HowardHinnant/date/blob/
> 0e65940a7fbc4ed617a1ee111a60311eccbead9a/src/tz.cpp#L3936
> 
> The intent seems to be clear -- apply a lot of heuristics to try to match
> what libc would do as closely as possible.

The intent is to infer an IANA time zone from the /etc/localtime symlink, if
possible. If the intent was to match libc, it would look at $TZ. I've discussed
this exact question with the author of that library (which is the origin of the
std::chrono components too). What I said in comment 8 above is paraphrasing
what he said.

> Even on Linux there are no guarantees whatsoever that it is possible to
> extract a IANA time zone from /etc/localtime.

And so current_zone() can fail.

> In fact, the problem is
> exactly identical to that with $TZ, if not worse -- $TZ is normally an IANA
> time zone name, whereas /etc/localtime is a symlink (but sometimes a
> hardlink or a copy) of a file in some OS-specific directory  (sometimes, but
> not always, /usr/share/zoneinfo) where the name of the file relative to the
> base directory is a IANA time zone name.

If $TZ is an IANA name then you can just look that name up with locate_zone,
it's easy.

If $TZ is a POSIX time zone spec, things are more complicated.

So the most we could do is handle the easy case, but not in a thread-safe way
(because the environment is mutable and not synchronized). So we could support
something that is already easy for users to do, by introducing possible data
races into the program. That doesn't seem like a good trade off to me. Just do
the easy thing yourself.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (11 preceding siblings ...)
  2024-04-09 16:40 ` redi at gcc dot gnu.org
@ 2024-04-09 17:19 ` hristo at venev dot name
  2024-04-09 23:29 ` harald at gigawatt dot nl
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: hristo at venev dot name @ 2024-04-09 17:19 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #13 from Hristo Venev <hristo at venev dot name> ---
> $TZ allows you to override it per-process (and even change it during the lifetime of a process by using setenv and tzset). We don't support that for current_zone().

/etc/localtime can also change.

> The intent is to infer an IANA time zone from the /etc/localtime symlink, if possible. If the intent was to match libc, it would look at $TZ. I've discussed this exact question with the author of that library (which is the origin of the std::chrono components too). What I said in comment 8 above is paraphrasing what he said.

Point taken. Still, do you have any explanation for why this behavior was
chosen?

> Just do the easy thing yourself.

The easy thing being to fix all applications that currently use or will ever
use current_zone(). Fun times ahead...

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (12 preceding siblings ...)
  2024-04-09 17:19 ` hristo at venev dot name
@ 2024-04-09 23:29 ` harald at gigawatt dot nl
  2024-04-09 23:29 ` redi at gcc dot gnu.org
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: harald at gigawatt dot nl @ 2024-04-09 23:29 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

Harald van Dijk <harald at gigawatt dot nl> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |harald at gigawatt dot nl

--- Comment #14 from Harald van Dijk <harald at gigawatt dot nl> ---
(In reply to Jonathan Wakely from comment #8)
> None of libstdc++, LLVM libc++, MSVC STL or the
> date/tz.h reference implementation uses $TZ for chrono::current_zone,

This does not appear to be accurate.

libc++ appears to always uses $TZ on POSIX-like platforms if it is set:
https://github.com/llvm/llvm-project/blob/788be0d9fc6aeca548c90bac5ebe6990dd3c66ec/libcxx/src/tzdb.cpp#L708
MSVC STL calls into __icu_ucal_getDefaultTimeZone. ICU's
ucal_getDefaultTimeZone uses the platform-specific way of getting the default
time zone, which on POSIX-like platforms does check getenv("TZ"), although of
course MSVC's STL would not likely be used on POSIX-like platforms.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (13 preceding siblings ...)
  2024-04-09 23:29 ` harald at gigawatt dot nl
@ 2024-04-09 23:29 ` redi at gcc dot gnu.org
  2024-04-09 23:43 ` redi at gcc dot gnu.org
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-09 23:29 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #15 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Hristo Venev from comment #13)
> > $TZ allows you to override it per-process (and even change it during the lifetime of a process by using setenv and tzset). We don't support that for current_zone().
> 
> /etc/localtime can also change.

But not in a racy way. The filesystem serializes those changes so that
inspecting the symlink with readlink(3) gives a single race-free answer at any
one time. And if the application wants to query current_zone() once and then
reuse the result of that query, it can, because the time_zone* is a value held
by the application itself. That's an advantage of the std::chrono design which
is absent from libc, where the application has very little control over the
hidden state that libc maintains for time zone info.

> > The intent is to infer an IANA time zone from the /etc/localtime symlink, if possible. If the intent was to match libc, it would look at $TZ. I've discussed this exact question with the author of that library (which is the origin of the std::chrono components too). What I said in comment 8 above is paraphrasing what he said.
> 
> Point taken. Still, do you have any explanation for why this behavior was
> chosen?

Because the environment cannot be accessed safely, and because $TZ was
traditionally used for POSIX time zones, which are inferior to the IANA zones
in nearly every way (see the "POSIX style time zones" section of
https://stackoverflow.com/tags/timezone/info for more details).

> > Just do the easy thing yourself.
> 
> The easy thing being to fix all applications that currently use or will ever
> use current_zone(). Fun times ahead...

Well they should not be assuming current_zone() uses $TZ in the first place -
that has never been claimed or documented by any reputable source. You only
need to "fix" the ones that were relying on something that was never part of
the API.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (14 preceding siblings ...)
  2024-04-09 23:29 ` redi at gcc dot gnu.org
@ 2024-04-09 23:43 ` redi at gcc dot gnu.org
  2024-04-09 23:47 ` redi at gcc dot gnu.org
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-09 23:43 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #16 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Harald van Dijk from comment #14)
> (In reply to Jonathan Wakely from comment #8)
> > None of libstdc++, LLVM libc++, MSVC STL or the
> > date/tz.h reference implementation uses $TZ for chrono::current_zone,
> 
> This does not appear to be accurate.
> 
> libc++ appears to always uses $TZ on POSIX-like platforms if it is set:
> https://github.com/llvm/llvm-project/blob/
> 788be0d9fc6aeca548c90bac5ebe6990dd3c66ec/libcxx/src/tzdb.cpp#L708

... incorrectly though?

I would expect TZ=:Europe/London to work according to POSIX, but it seems they
don't remove the ':' before the lookup. So it only works for a string like
"MST7MDT" which means only the following entries in the IANA database can be
matched by a value in $TZ:

Z CET 1 c CE%sT
Z CST6CDT -6 u C%sT
Z EET 2 E EE%sT
Z EST -5 - EST
Z EST5EDT -5 u E%sT
Z Factory 0 - -00
Z HST -10 - HST
Z MET 1 c ME%sT
Z MST -7 - MST
Z MST7MDT -7 u M%sT
Z PST8PDT -8 u P%sT
Z WET 0 E WE%sT

That doesn't seem very well thought out or tested.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (15 preceding siblings ...)
  2024-04-09 23:43 ` redi at gcc dot gnu.org
@ 2024-04-09 23:47 ` redi at gcc dot gnu.org
  2024-04-09 23:50 ` harald at gigawatt dot nl
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-09 23:47 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #17 from Jonathan Wakely <redi at gcc dot gnu.org> ---
And "Factory" isn't a valid POSIX zone, so remove that one from the list. So if
I'm reading it correctly, some European zones and the US zones can be used in
$TZ with libc++ but most IANA zones won't work. And then it just silently
ignores $TZ and falls back to /etc/localtime so an application still can't
actually rely on $TZ being used. It might work, for a small set of zones, or it
might not work.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (16 preceding siblings ...)
  2024-04-09 23:47 ` redi at gcc dot gnu.org
@ 2024-04-09 23:50 ` harald at gigawatt dot nl
  2024-04-09 23:57 ` redi at gcc dot gnu.org
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: harald at gigawatt dot nl @ 2024-04-09 23:50 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #18 from Harald van Dijk <harald at gigawatt dot nl> ---
(In reply to Jonathan Wakely from comment #16)
> ... incorrectly though?

Given that you have expressed your view that *any* attempt at using TZ is
inherently incorrect, I am not surprised that you view libc++'s attempt as
incorrect. :)

I am not intending to get involved in discussion of what the correct behaviour
is, I merely wanted to correct the record about what other implementations do.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (17 preceding siblings ...)
  2024-04-09 23:50 ` harald at gigawatt dot nl
@ 2024-04-09 23:57 ` redi at gcc dot gnu.org
  2024-04-10  0:07 ` redi at gcc dot gnu.org
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-09 23:57 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #19 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jonathan Wakely from comment #16)
> I would expect TZ=:Europe/London to work according to POSIX,

Well, POSIX says ":characters" is implementation-defined, but for Glibc it
looks up an IANA zone.

I would also expect "<MST>7<MDT>" to work, since the current POSIX spec
describes that.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (18 preceding siblings ...)
  2024-04-09 23:57 ` redi at gcc dot gnu.org
@ 2024-04-10  0:07 ` redi at gcc dot gnu.org
  2024-04-10  0:26 ` harald at gigawatt dot nl
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-10  0:07 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #20 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Harald van Dijk from comment #18)
> (In reply to Jonathan Wakely from comment #16)
> > ... incorrectly though?
> 
> Given that you have expressed your view that *any* attempt at using TZ is
> inherently incorrect, I am not surprised that you view libc++'s attempt as
> incorrect. :)

That's not what I mean. I do consider it ill-advised and unsafe to use TZ
(since getenv can introduce data races, and I don't think they document
potentially concurrent calls to current_zone() and setenv as being unsafe), but
libc++ is free to define current_zone() that way if they think that is right
for their users. The comment in libc++ notes other problems like the lifetime
and ownership one I noted in comment 8, and the inconsistency between "MST"
being recognized as an IANA zone but "MST-3" not being. They say "the
documentation is unclear" but I disagree, "MST-3" is perfectly valid according
to POSIX. And so is TZ="garbage23nonsense", because there is no requirement in
POSIX for POSIX-style time zone definitions to have any relation to a real IANA
zone. The std and dst names in a POSIX zone are effectively arbitrary.

Glibc gets this right:
$ date
Wed 10 Apr 01:04:17 BST 2024
$ TZ=garbage23nonsense date
Tue  9 Apr 02:04:18 nonsense 2024

But quite aside from that, my point in comment 16 is that if they're going to
use TZ, I would expect TZ=":Europe/London" to work.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (19 preceding siblings ...)
  2024-04-10  0:07 ` redi at gcc dot gnu.org
@ 2024-04-10  0:26 ` harald at gigawatt dot nl
  2024-04-10  0:57 ` redi at gcc dot gnu.org
  2024-04-10  1:10 ` redi at gcc dot gnu.org
  22 siblings, 0 replies; 24+ messages in thread
From: harald at gigawatt dot nl @ 2024-04-10  0:26 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #21 from Harald van Dijk <harald at gigawatt dot nl> ---
(In reply to Jonathan Wakely from comment #20)
> (In reply to Harald van Dijk from comment #18)
> > (In reply to Jonathan Wakely from comment #16)
> > > ... incorrectly though?
> > 
> > Given that you have expressed your view that *any* attempt at using TZ is
> > inherently incorrect, I am not surprised that you view libc++'s attempt as
> > incorrect. :)
> 
> That's not what I mean.

You wrote in <https://gcc.gnu.org/pipermail/libstdc++/2023-May/055933.html>
which you referenced in comment #1: "And in any case, I don't think we want to
depend on $TZ. That's not the intended design of the std::chrono API." Earlier
in that thread, you had written in
<https://gcc.gnu.org/pipermail/libstdc++/2023-May/055928.html>: "In any case,
the C++ standard requires that current_zone() refers to the computer's zone,
not just the current process' TZ setting:"

It's fine if you changed your mind since then, but it is hard for me to read
this as any other way than that any attempt at using TZ is inherently
incorrect.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (20 preceding siblings ...)
  2024-04-10  0:26 ` harald at gigawatt dot nl
@ 2024-04-10  0:57 ` redi at gcc dot gnu.org
  2024-04-10  1:10 ` redi at gcc dot gnu.org
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-10  0:57 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #22 from Jonathan Wakely <redi at gcc dot gnu.org> ---
I do still consider it incorrect. 

But what I mean re libc++ is that *even ignoring* the general problems with
using TZ, *their implementation* of using TZ isn't even correct. If the
intention is to follow POSIX, it fails to do that.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Bug libstdc++/114645] std::chrono::current_zone ignores $TZ on Linux
  2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
                   ` (21 preceding siblings ...)
  2024-04-10  0:57 ` redi at gcc dot gnu.org
@ 2024-04-10  1:10 ` redi at gcc dot gnu.org
  22 siblings, 0 replies; 24+ messages in thread
From: redi at gcc dot gnu.org @ 2024-04-10  1:10 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114645

--- Comment #23 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Re https://github.com/cplusplus/draft/issues/6922

It can't possibly mean that the returned time zone *needs* to be the same as
the C library, because that's impossible in general, because the C library
isn't required to use IANA zones at all. See my TZ=garbage23nonsense example.
There is no way to match that with std::chrono::time_zone without pointer
lifetime issues and inconsistencies like returning a time_zone that isn't in
the tzdb.

And if the C++ standard intended to require that TZ is respected on POSIX
systems, then it would say so. The absence of any requirement means it's not
required. TZ is not mentioned in the standard at all. The standard probably
isn't going to say it *must not* be used, because it's not in the business of
listing (or forbidding) possible vendor extensions. There might be systems
where a TZ environment var is the only way the time zone can be set, and it
always is an IANA zone. But I don't believe any of the targets libstdc++
supports fit into that category.

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2024-04-10  1:10 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-08 19:01 [Bug libstdc++/114645] New: std::chrono::current_zone ignores $TZ on Linux hristo at venev dot name
2024-04-08 19:27 ` [Bug libstdc++/114645] " redi at gcc dot gnu.org
2024-04-08 20:23 ` hristo at venev dot name
2024-04-08 20:25 ` redi at gcc dot gnu.org
2024-04-08 20:46 ` hristo at venev dot name
2024-04-08 20:48 ` redi at gcc dot gnu.org
2024-04-08 20:51 ` redi at gcc dot gnu.org
2024-04-08 20:56 ` hristo at venev dot name
2024-04-09  9:19 ` redi at gcc dot gnu.org
2024-04-09  9:41 ` hristo at venev dot name
2024-04-09  9:46 ` xry111 at gcc dot gnu.org
2024-04-09  9:49 ` hristo at venev dot name
2024-04-09 16:40 ` redi at gcc dot gnu.org
2024-04-09 17:19 ` hristo at venev dot name
2024-04-09 23:29 ` harald at gigawatt dot nl
2024-04-09 23:29 ` redi at gcc dot gnu.org
2024-04-09 23:43 ` redi at gcc dot gnu.org
2024-04-09 23:47 ` redi at gcc dot gnu.org
2024-04-09 23:50 ` harald at gigawatt dot nl
2024-04-09 23:57 ` redi at gcc dot gnu.org
2024-04-10  0:07 ` redi at gcc dot gnu.org
2024-04-10  0:26 ` harald at gigawatt dot nl
2024-04-10  0:57 ` redi at gcc dot gnu.org
2024-04-10  1:10 ` redi at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).