Search code examples
clanguage-lawyerstrftime

strftime and nonnormalized dates/times


Most definitions of strftime's %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.)

[Full disclosure: I am posting the same question to the tz mailing list.]


Solution

  • The C11 standard 7.27.3.5/3 says:

    If any of the specified values is outside the normal range, the characters stored are unspecified.

    Which I take to mean that the input must be normalized for the function to behave correctly; and a conforming implementation of strftime might operate by naively reading and displaying the values stored in the struct without performing any analysis on them.