Date: Tue, 25 Oct 2022 04:08:13 +0300 From: Valery Ushakov <u...@stderr.spb.ru> Message-ID: <Y1c2/di8seq1o...@pony.stderr.spb.ru>
| 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