[tz] Buggy %z behaviour in strftime

Paul Eggert eggert at cs.ucla.edu
Mon Jul 18 17:19:29 UTC 2022

On 7/18/22 09:03, Paul Eggert wrote:
> I suppose someone should file a defect report with the C standardization 
> committee.

I found what I hope is the correct email address for that (it's not 
well-advertised) and submitted the following bug report:


Subject: strftime %z and %Z depend on more than just tm_isdst

A recent discussion in the Time Zone Database mailing list 
<https://mm.icann.org/pipermail/tz/2022-July/031674.html> has prompted 
me to file this bug report against the C standard.

Draft N2912, section "The strftime function", pages 365-6, 
paragraph 3 says that the %z and %Z conversion specifiers examine only 
the tm_isdst members of the passed-in structure. However, this is not 
how many implementations actually behave.

Some implementations (e.g., AIX, Solaris) infer %z and %Z output from 
tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, and tm_isdst, and 
therefore sometimes guess %z or %Z output incorrectly when the clock 
moves back from one standard time to another (e.g., Iran at the end of 
the year 1978). These implementations typically also depend on the 
current setting of the TZ environment variable.

Other implementations (e.g., FreeBSD, GNU/Linux) get the UT offset and 
abbreviation from struct tm members tm_gmtoff and tm_zone that are not 
specified by the C standard. These implementations do not have to guess 
%z and %Z output; however, they require that the nonstandard members be 
filled in correctly by localtime or equivalent.

Implementations that conform to the standard's current wording cannot 
handle anything more complicated than a time zone with just one standard 
time offset and abbreviation, which means they cannot handle timestamps 
for locations like Iran, Portugal, etc., that have changed their 
standard-time offset. The C standard should not require implementations 
to be so limited that they cannot handle common timekeeping situations.

A simple fix for this issue is to require applications to initialize a 
struct tm as if by localtime or equivalent, before passing the struct tm 
to strftime. This is what applications need to do anyway, if they want 
to be portable to real-world systems such as AIX, FreeBSD, GNU/Linux, 
Solaris, etc.

Proposed fix:

1. Remove the two instances of "[tm_isdst]" in the %z and %Z entries in 
Draft N2912, section "The strftime function", pages 365-6, 
paragraph 3.

2. Add the following text to that paragraph:

If the %z and %Z conversion specifiers are used, the broken-down time 
structure pointed to by timeptr shall contain values generated by a 
successful previous call to gmtime, gmtime_r, gmtime_s, localtime, 
localtime_r, localtime_s, or mktime.

More information about the tz mailing list