[tz] strftime %s
Paul Eggert
eggert at cs.ucla.edu
Sun Jan 14 06:51:14 UTC 2024
On 2024-01-13 17:46, Robert Elz wrote:
> but unless you have some way
> to guarantee that the aplication has set the unspecified fields
> of the tm struct, referencing any of them may be referncing uninit'd
> date, and that is undefined behaviour
It's not necessarily undefined behavior because we're talking about a
standard library function, and (as you mentioned elsewhere) such
functions need not be implemented in standard C.
More important, the draft POSIX standard is simply wrong if it says
strftime can't look at (for example) tm_gmtoff when calculating %z,
because many implementations do exactly that and we shouldn't invalidate
them all. (One example is given below.)
> | In general strftime cannot ignore all the other information,
> | as in general strftime must look at the TZ setting
>
> Only for %s
In POSIX 2017 strftime must also look at TZ for %Z and %z, and that
hasn't changed in POSIX 202x/D3. (Admittedly this is a messy area and
the draft doesn't get this area right.)
> that is specified by reference to mktime() which
> is where the TZ reuirment appears (via tzset())
That's another place where the POSIX draft gets things wrong. I'm not
talking about issues with mktime itself (it's dicey for other reasons,
but that is a separate matter); I'm talking about where draft POSIX
mistakenly says strftime needs mktime (or equivalent) to implement %s.
> If there is no
> use of %s strftime() should not go near TZ.
First, an implementation of POSIX 202x/D3 strftime doesn't need to go
near TZ to implement any conversion, not even %s. tzcode strftime no
longer relies on TZ as of today's patch, and this is fine.
Second, the POSIX draft requires strftime to act as if it calls tzset,
which means strftime *must* go near TZ even if %s is not used, if only
so that strftime conforms to this no-longer-useful POSIX requirement.
> | and the LC_CTYPE category.
>
> Yes. That one is explicit.
Where? I don't see LC_CTYPE mentioned anywhere in the strftime section
(202x/D3 lines 69411-69832). Obviously LC_CTYPE is essential but it's
not explicitly called out in strftime's description.
I mentioned LC_CTYPE only because it's another example of something that
strftime can use to calculate conversions, something that is not
explicitly mentioned in the spec; and this demonstrates that the set of
things that strftime can use is not exhaustive.
> If you have some way to guarantee that referencing any uninit'd
> fields wont have consequences you don't want to have hapoen, then
> go ahead and do it.
We have that in tzcode, with UNINIT_TRAP. (It's a guarantee by the
implementer.)
> Yes, if you're being strictly C conforming, then you cannot access
> tm_gmtoff, as C doesn't demand that field exist, so conforming portable
> C applications cannot be expected to have set it. POSIX does required
> it (will require it when this new standard appears) and so applications
> written to conform to that standard will know to set that field.
> Older applications will not, so accessing it for them is risky.
This interpretation is too strict, and it doesn't correspond to how
implementations behave. For example:
#include <stdio.h>
#include <time.h>
static void
f (int gmtoff)
{
char buf[100];
struct tm tm;
tm.tm_gmtoff = gmtoff;
tm.tm_isdst = 0;
strftime (buf, sizeof buf, "%z", &tm);
printf ("%%z formats as '%s' with tm_isdst=%d, tm_gmtoff=%ld\n",
buf, tm.tm_isdst, tm.tm_gmtoff);
}
int
main ()
{
f (0);
f (3600);
}
On my Ubuntu 23.10 platform with TZ="America/Los_Angeles" this outputs:
%z formats as '+0000' with tm_isdst=0, tm_gmtoff=0
%z formats as '+0100' with tm_isdst=0, tm_gmtoff=3600
If the abovementioned interpretation were correct, then to conform to
POSIX-2017, strftime %z could look *only* at tm_isdst and could not look
at tm_gmtoff, and the Ubuntu behavior would therefore be incorrect
because its strftime is clearly looking at tm_gmtoff.
But the Ubuntu behavior *is* correct: it's good behavior, it's the
behavior most people would expect, and it's common on many
implementations. If an interpretation of the C and/or POSIX standards
says that Ubuntu doesn't conform, then either the standards are wrong or
the interpretation is wrong. My previous email today gave an alternate
interpretation under which the Ubuntu behavior is conforming, and I
expect that this is the best way out of this mess.
> I'm not sure what the proposed patch is, or what
> it is intending to fix
It intends to fix the bug reported by Dag-Erling Smørgrav here:
https://mm.icann.org/pipermail/tz/2024-January/033488.html
Without the patch, the bug occurs even on systems with tm_gmtoff.
> | or that would add new functions strftime_z and strftime_lz which
> | would also cause significant pain.
>
> No, adding new funxtions is easy
True, it's easier for implementers to add functions than to add struct
tm members. However, it's still a pain for users as it requires them to
use a new API simply because they want %z, %Z and %s to work sanely.
In contrast, today's proposed tzcode patch means no change to the API,
avoiding this unnecessary pain.
More information about the tz
mailing list