tech-userlevel archive

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

Re: candidate strftime docs patch



I have no problem with the proposed patch to strftime.3
though I'd word the change for %s more like it is in the
GNU and POSIX specifications, to make it clear that the
value that %s represents as a string is the identical
value that mktime() would return if given the same struct tm.

It would also be worth adding something to indicate that
the results are unspecified (unlike mktime(), but including
the %s conversion which uses mktime() somewhat weirdly)
if any of the fields in the struct tm are out of range.

Note that the standards actually say out of range of the
values specified in <time.h> - which says, for example,
that for tm_mday the range is [1..31] which makes sense, some
months have 31 days.   That would mean that as specified,
a struct tm with tm_mday==30 and tm_mon==10 (November, the
months are origin 0 ... one of the historical quirks of
all of this) would not be considered to have any values
which are out of range - which is not really what anyone
(implementation, or human) believes to be true.   Similarly
tm_mon==1 and tm_mday==31 would be in range...  That this
avoids strftime() producing unspecified results is not the
problem (printing "31 Feb 2022" is what would happen in the
latter case, that's fine, if idiotic, but gigo).  What
matters more is when used with mktime() which is only
actually permitted to modify the fields which are out
of range of what <time.h> secifies (and purely by implication,
it isn't written in the standard, other fields which ought
to be adjusted to compensate for the field being reduced to
be within range).

That is, the intent (though it isn't stated) is that one can do

	tm = localtime(&t);
	tm->tm_mday += 3;
	t = mktime(tm);

and in addition to that being a kind of baroque way to
write
	t += 86400 * 3;

(it does avoid needing to deal with potential overflow of t,
since tm_mday is an int, and localtime() is restricted to
only put values 1..31 in it, the += 3 cannot overflow, as long
as int is at least 7 bits - and nothing allows int to be that
small - hence no need for any overflow protection, other than
checking the values of t and errno after the mktime()).

The resulting struct tm (a value/result parameter) from mktime()
is intended to be exactly the same as would reault from a call of
localtime(&t) on the resulting t (assuming mktime() did not fail).
That is, if the original t represented Feb 28, and not in a leap year,
the answer should represent Mar 3 (or Mar 2 in a leap year), not Feb 31
- but it is not clear from the specs that the standard actually allows that
to happen.

Apologies for the irrelevant side ramble there, none of that
has anything do do with strftime.3


The proposed change to tm.3 [aside: wtf is this in section 3?
Surely it belongs in section 5 or something ??] I would word
differently however.

It doesn't really help to talk about "informational" fields,
or anything related.

I'd simply say something like:

	When passing a struct tm to a library routine, the
	fields that it is to access must be set to appropriate
	values, as defined by that function, other fields need
	not be initialised.

Of course, that then places the burden on asctime(3), mktime(3),
and strftime(3) to actually correctly document the fields that are
used (and for strftime that means for each conversion specifier, as
it is done in the standards, though not necessarily using the same
technique - one could instead provide a table of the fields of
the struct, and for each, give a list of which conversions use that
field (and hence require it to be set).   Only the fields that some
conversion requires need be mentioned at all - with some text indicating
that any other fields of struct tm not mentioned are not required by
any conversion (which applies to tm_zone and tm_gmtoff in the current
implementation).

Anything else accepts a struct tn as an arg as well of course.

kre



Home | Main Index | Thread Index | Old Index