[tz] strftime and nonnormalized dates/times

Steve Summit scs at eskimo.com
Tue Jul 3 02:13:51 UTC 2018

I have a question about the strftime function.  This is not
related to time zones per se, but there are a lot of date/time
programming experts here, and of course there's a reference
implementation of strftime in tzcode.

[Full disclosure: I am posting the same question to
StackOverflow: https://stackoverflow.com/questions/51145727/ .]

Most definitions of the %H, %M, and %S specifiers (including
those in the ANSI/ISO C Standards) contain language like

	%H   is replaced by the hour (24-hour clock)
	     as a decimal number (00-23).

Now, that little notation "(00-23)" at the end tells you the
range of numbers you're going to see *if the struct tm you're
printing was just created by localtime or gmtime*.

My question concerns the presence or absence of a requirement
that the struct tm being referenced by strftime *must* have been
one just generated by localtime or gmtime.  I don't think there's
such a requirement, but if there isn't, those notations "(00-23)"
and "(00-59)" don't really have any normative implications for
strftime -- they're more of a misplaced requirement on the values
generated by localtime and gmtime.

But if strftime doesn't restrict the ranges of the various struct
tm fields to their "normal" values, it makes me wonder how much
latitude a push-the-boundaries programmer actually has when
calling strftime.  Are the values as unlimited as they are when
calling, say, mktime?

To make the question more concrete, it came to me when I found
myself writing this code:

	time_t dt = t2 - t1;
	struct tm *tmp = gmtime(&dt);
	if(dt > 86400)
		tmp->tm_hour += dt / 86400 * 24;
	strftime(etbuf, sizeof(etbuf), "elapsed: %H:%M:%S", tmp);

That is, I'm subtracting two times, and letting gmtime and
strftime convert the difference to HH:MM:SS format for me.
But if the time delta was more than a day, I'm not printing it
as days; I'm just lumping it in with the hours (which, it's true,
might end up being a very large number if there were months or
years between t1 and t2).

So, language lawyer question: Is this legal and portable?
When calling strftime, are tm_hour, tm_min, and the rest
limited to their normal ranges, or not?  (Yes, I've tried it,
and nonnormalized values work -- not at all surprisingly --
as expected under the popular implementations, but that's not
the question.)

More information about the tz mailing list