[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