tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: strftime(3) oddities with %s, %z
Date: Tue, 25 Oct 2022 04:08:13 +0300
From: Valery Ushakov <uwe%stderr.spb.ru@localhost>
Message-ID: <Y1c2/dI8SeQ1Oz8c%pony.stderr.spb.ru@localhost>
| strftime(3) %s format is not in ISO C or POSIX, though the rumor is
| that it will be in the next POSIX version.
It will be. The text is:
s Replaced by the number of seconds since the Epoch as a decimal number,
calculated as described for mktime( ). [all members]
For what it is worth, since we are here, tm_zone and tm_gmtoff will be
in the next POSIX as well. That change I was personally hesitant about,
not because they're not a good idea (they are - except that the lifetime
of the string pointed to by tm_zone is kind of peculiar, and could do to
have been improved) but because adding those fields for implementations
that don't already have them is going to be a disaster for their ABI.
Not an issue for NetBSD of course.
| The problem though is that mktime(3) is specified to convert tm
| "expressed as local time".
Yes, that is not a problem though, it is how it is specified to work.
Everything in strftime() takes the struct tm as being in local time.
(That's why NetBSD has strftime_z()).
| The test below produces ("g" is for tm from gmtime, "l" is for tm from
| localtime):
I am not sure that calling strftime() on something obtained from gmtime()
makes any sense. If one wants UTC conversions, either use strftime_z()
(not a POSIX interface) or set the timezone to UTC (tzset() with TZ="UTC").
| time_t mktime %s %F %T (%z)
| netbsd:
| g: 1659968100 -> 1659957300 = 1659957300: 2022-08-08 14:15:00 (+0300)
| l: 1659968100 -> 1659968100 = 1659968100: 2022-08-08 17:15:00 (+0300)
That looks correct to me, mktime().
| glic:
| g: 1659968100 -> 1659957300 = 1659957300: 2022-08-08 14:15:00 (+0000)
| l: 1659968100 -> 1659968100 = 1659968100: 2022-08-08 17:15:00 (+0300)
That's almost correct, the zone name hasn't been filled in, mktime()
(which strftime("%s") is intended to call, or at least equivalent
functionality, should fill in the local zone offset in tm_gmtoff,
though until the next standard appears, since tm_gmtoff, that is
obviously not a requirement). That is, once mktime() has been
called, which came before the %z conversion, the gmtoff should have
been set to represent local time.
| g: 1659968100 -> 1659957300 = 1659968100: 2022-08-08 14:15:00 (+0000)
| l: 1659968100 -> 1659968100 = 1659968100: 2022-08-08 17:15:00 (+0300)
The g entry there is simply wrong (as %s and mktime() are defined). The
result from mktime() (1659957300 there) is required to be what %s produces.
| Note that both netbsd and glibc adjust the %s value by the local tz
| offset for struct tm returned by gmtime.
That's what they're required to do. mktime() does not examine anything
except the tm_sec tm_min tm_hour tm_mday tm_mon tm_year and tm_isdst
fields - it sets the others to appropriate values as a side effect (it
also sets tm_isdst if its entry value was -1).
| Note that netbsd additionally gets the %z wrong for the tm obtained
| from gmtime(3).
Not wrong, just unexcpected, but the situation shouldn't arise, as
a tm from gmtime shouldn't be being passed to strftime at all (and
certainly not if %s is used).
kre
Home |
Main Index |
Thread Index |
Old Index