[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