tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: strftime(3) oddities with %s, %z



On Thu, Oct 27, 2022 at 09:06:26PM +0700, Robert Elz wrote:
 >   | I don't see how POSIX proposing to define a function to produce a
 >   | wrong (and completely meaningless, no less!) answer makes it correct.
 > 
 > The answer is neither wrong nor meaningless, it simply doesn't
 > do what you might have wanted it to do.   For typical uses (I use %s
 > all the time, generally via "date +%s") it works exactly as intended.
 > It also works when used as "date -u +%s" (both of these uses might have
 > a -r or -d option to set the time desired, rather than just "now"), as
 > date -u is set up to use UTC correctly.

"%s    is replaced by the number of seconds since the Epoch"

That is, it's supposed to print the time_t value. In the context of
time_t as it's universally known, there is no timezone offset and no
timezone handling; it is the absolute time (modulo leap second issues,
which are an entirely different issue) and timezones are only
introduced when times are prepared for printing.

This is a fundamental design property of Unix time handling. Changing
it would be a mistake.

Changing it just in this particular corner because of an
implementation defect is particularly silly.

 > Further, what POSIX is doing (it is already in the drafts) is specifying
 > what the implementations (including ours, and glibc) actually do.  That's
 > what the users should expect to happen.

No, there is no obligation to standardize incorrect behavior. When
existing implementations have incorrect or variant behavior they don't
want to bother to fix, the correct response by the standards committee
is to make the result unspecified, or implementation-defined, or put
it in some other similar category.

For my part, I had never had any idea you couldn't use strftime with
gmtime() results, and I'm pretty sure I have done so at times, going
back all the way to when I first met this interface in Turbo C in the
1980s. Nor is there any reason to suspect that it wouldn't work. So I
consider this whole thing a significant violation of the principle of
least surprise.

 > If you want something different, implement that, and then get the rest
 > of the implementations to actually adopt it - and then propose it to
 > POSIX, you never know, it might appear in the standard following the
 > next one (in another 5-10 years).

Standardizing what is clearly _wrong_ behavior precludes fixing it.

 > I will look into the timezone stuff in strftime(), but from when I glanced
 > at it yesterday, it seemed to be simply using what is in the struct tm,
 > passed in, so it may be that gmtime() isn't putting something useful in
 > those fields (after all, if you're using gmtime() you ought to know that
 > the zone name is GMT or UTC (your pick) and that the offset is 0).   It
 > is also perhaps affected by tm_isdst, which I assume gmtime() always sets
 > to 0.

It looked to me like it was probably built with the wrong ifdefs, but
maybe not. I didn't look very hard either.

 > It would help if you shared the "./test" program you used (source, doesn't
 > matter how crufty - I understand quick and dirty tests) so I can reproduce
 > your results.

Nothing surprising:

   ------

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

static void print(const char *desc, struct tm *tm) {
   char buf[256];

   strftime(buf, sizeof(buf), "%c %Z %z (%s)", tm);
   printf("%s: %s\n", desc, buf);
}

int main(int argc, char *argv[]) {
   time_t timer;

   timer = atol(argv[1]);
   print("gmtime", gmtime(&timer));
   print("localtime", localtime(&timer));

   return 0;
}

   ------

Results don't depend on the order of the print calls. In the local
environment here, $TZ isn't set explicitly by default, and
/etc/localtime points to US/Eastern.

-- 
David A. Holland
dholland%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index