[tz] Buggy %z behaviour in strftime

Paul Eggert eggert at cs.ucla.edu
Mon Jul 18 16:03:11 UTC 2022


On 7/18/22 03:04, Michael H Deckers via tz wrote:
> 
>      By the way, the draft standard seems to be defective in that
>      it does not state that strftime() also looks at the members
>      .tm_year, .tm_mon, tm_mday, .tm_hour, .tm_min, .tm_sec
>      for printing %z or %Z -- one cannot determine the offset
>      or the time zone abbreviation without knowing the timestamp.

Good point, and POSIX and the C standard are both wrong here. In 
practice, some implementations guess from the members that you mention 
(and therefore sometimes guess wrong), whereas others look at the 
nonstandard members tm_gmtoff and tm_zone (and therefore get the answer 
right if you've filled in the struct tm with localtime). Although all 
these implementations violate POSIX and the C standard (because they all 
look somewhere other than tm_isdst) that's a bug in the standards, not 
in the implementations.

I suppose someone should file a defect report with the C standardization 
committee. (The C standard's spec for %z is also messed up: it's not 
clear whether four digits of output are required. POSIX doesn't have 
this problem.) I don't know how to navigate through the C standard 
bureaucracy, though.

On 7/18/22 02:34, Almaz Mingaleev via tz wrote:
> is
> there any downside of "doing the right thing" (tm) and
> instead of using user provided tm_gmtoff get it from mktime
> call?

One downside is that it's slower. More important, it can give the wrong 
answer in cases where mktime guesses wrong. (Many mktime implementations 
use the user-supplied tm_gmtoff to get the right answer - but if you're 
relying on that there's no point to calling mktime.)

Attached is an example program where the strftime implementations that 
guess go wrong. On tzcode, GNU/Linux, FreeBSD, etc. (which use tm_gmtoff 
and tm_zone and so do not guess) this program prints:

1.  283981500 = 1978-12-31 23:45:00 +0400 (+04) standard

2.  283983300 = 1978-12-31 23:45:00 +0330 (+0330) standard

3. 1640982600 = 2022-01-01 00:00:00 +0330 (+0330) standard

4. 1656617400 = 2022-07-01 00:00:00 +0430 (+0430) daylight

5.  283981500 = 1978-12-31 23:45:00 +0400 (+04) standard

6.  283983300 = 1978-12-31 23:45:00 +0330 (+0330) standard

7. 1640982600 = 2022-01-01 00:00:00 +0330 (+0330) standard

8. 1656617400 = 2022-07-01 00:00:00 +0430 (+0430) daylight


which is the correct answer. On Solaris 10 (which guesses) this prints:

1.  283981500 = 1978-12-31 23:45:00 +0330 (+0330) standard

2.  283983300 = 1978-12-31 23:45:00 +0330 (+0330) standard

3. 1640982600 = 2022-01-01 00:00:00 +0330 (+0330) standard

4. 1656617400 = 2022-07-01 00:00:00 +0430 (+0430) daylight

5.  283981500 = 1978-12-31 23:45:00 +0330 (+0330) standard

6.  283983300 = 1978-12-31 23:45:00 +0330 (+0330) standard

7. 1640982600 = 2022-01-01 00:00:00 +0330 (+0330) standard

8. 1656617400 = 2022-07-01 00:00:00 +0430 (+0430) daylight


and lines 1 and 5 are wrong. On AIX 7.2 (which guesses in a different 
way) this prints:

1.  283981500 = 1978-12-31 23:45:00 +04 (+04) standard

2.  283983300 = 1978-12-31 23:45:00 +0330 (+0330) standard

3. 1640982600 = 2022-01-01 00:00:00 +0330 (+0330) standard

4. 1656617400 = 2022-07-01 00:00:00 +0430 (+0430) daylight

5.  283981500 = 1978-12-31 23:45:00 +0330 (+0330) standard

6.  283983300 = 1978-12-31 23:45:00 +0330 (+0330) standard

7. 1640982600 = 2022-01-01 00:00:00 +0330 (+0330) standard

8. 1656617400 = 2022-07-01 00:00:00 +0430 (+0430) daylight


and line 5 is wrong, and line 1 disagrees with line 5 even though 
they're both converting the same time_t value.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: tm_isdst.c
Type: text/x-csrc
Size: 739 bytes
Desc: not available
URL: <https://mm.icann.org/pipermail/tz/attachments/20220718/21de55bb/tm_isdst.c>


More information about the tz mailing list