Re: C Code for draft-newman-datetime-00.txt
In message <32DD304D.40D@Renault.FR>, Antoine Leca wrote:
I didn't change anything, but this raises a point: wouldn't it be better to pass a « time_t const *t » argument? This is for consistency with other library functions, and portability (particularly when time_t is a floating type).
This rises an interesting question: Why does the C library functions always access time_t values by constant pointers and not by simply copying the value??? I never understood this part of the C lib API. How is portability increased by not using a call-by-value here? If there is any good reason that this has been done in libc, then I'd of course also add it to my code. I already did it for consistency with the existing library functions, but I'd like to know why this is supposed to be the right thing to do.
¤ Comparing t with 0 doesn't take any sense (I know one system where ¤ (time_t)0 is J2000,0, so negative t are allowed before 2000-01-01 12:00:00Z
Ok, you are right. I just hope that the system you know does not encode 2000-01-01 11:59:59Z = (time_t) -1 as this value is reserved by the standard for error conditions.
¤ Basically, you can't trust strftime to output what you want if you ¤ don't set the locale to "C" before. ¤ I know this code is overkill in the vast majority of cases.
I just checked the standard again and it does not indicate that any of the conversion specifiers "%Y-%m-%d %H:%M:%S" depend on the locale. There ARE many conversion specifiers that depend on the locale, but not the above ones, so I understand that we do not have to switch to the "C" locale.
****** 8601.c if (prec > 0) { sprintf(buf, ".%09ld", nsec); buf += prec + 1; ****** 8601wrt.c if (prec > 0) { int i=9; while (i-->prec) nsec /= 10; sprintf(buf, ".%0*ld", prec, nsec); buf += prec + 1; ******
¤ I wrote this modification for avoiding a overflow of the buffer. ¤ You may consider it as unnecessary (but you then may consider ¤ issuing a warning in the man page).
I checked already that nsec is not out of range previously, so I think this additional check is redundant. Thanks for your good comments and also for those I received from others. I'll post the next revision here soon. Markus -- Markus G. Kuhn, Computer Science grad student, Purdue University, Indiana, USA -- email: kuhn@cs.purdue.edu
Why does the C library functions always access time_t values by constant pointers and not by simply copying the value???
I believe this was purely historical. Back in ancient times, the support for 32-bit integral quantities in the PDP-11 C compiler (I *did* say "ancient times"... :-)) was either absent or not quite ready (I vaguely remember that there might have been *some* stuff for "long" in the V6 PDP-11 C compiler, but that it wasn't documented and that it probably wasn't ready to use). As such, times were stored as arrays of two "int"s; the "time()" function took, as an argument, a pointer to the first member of such an array, so that, for example, if you did int now[2]; you could do time(now); and get "now" filled in with the current time. Eventually, "long" became supported, and times became "long"s (or "time_t"s, which were "long"s in PDP-11 UNIX and other UNIXes with 16-bit "int"s), but the APIs weren't fully cleaned up - "time()" was changed to return a "time_t", and to take either a pointer to a "time_t" or a NULL as an argument, with NULL meaning "don't fill this in", but "localtime()" wasn't changed to take a "time_t" as an argument, presumably for binary and/or source compatibility reasons.
I never understood this part of the C lib API. How is portability increased by not using a call-by-value here?
It increased portability to machines with C compilers with 16-bit "int"s and without adequate support for "long". :-)
If there is any good reason that this has been done in libc, then I'd of course also add it to my code. I already did it for consistency with the existing library functions, but I'd like to know why this is supposed to be the right thing to do.
I wouldn't say that, except *maybe* to make the calls look like existing calls, it's the right thing to do. The reasons why it was done in "libc" are compatibility with interfaces defined before 32-bit integral types were available, which may have been a good reason for existing interfaces but isn't necessarily a good reason for new interfaces.
This rises an interesting question:
Why does the C library functions always access time_t values by constant pointers and not by simply copying the value???
I never understood this part of the C lib API. How is portability increased by not using a call-by-value here?
Okay, all who remember the "portable C compliler" under v6 Unix raise your hand... Hmm, not too many hands up. The "long" datatype was not one that could be passed as a function parameter, nor returned as a function value, back in days of yore. But a (16 bit) int time() value wasn't big enough to hold any reasonable time inteval. So the time() function was passed a pointer to a long to fill, and the localtime(), gmtime() functions were passed pointers to longs (not time_t back in those days, just long ints) to make use of. The language evolved to permit longs, and later even structs, to be passed to and returned from functions, but the API of the time functions lives on.
If there is any good reason that this has been done in libc, then I'd of course also add it to my code. I already did it for consistency with the existing library functions, but I'd like to know why this is supposed to be the right thing to do.
The only reason is "historical practice". I feel that the existing C API is suboptimal in the design of its time functions, but I recognize that the weight of remaining compatible with what was then the only "existing practice" was too great for the ANSI C8x committee to change these APIs.
� Comparing t with 0 doesn't take any sense (I know one system where � (time_t)0 is J2000,0, so negative t are allowed before 2000-01-01 12:00:00Z
Ok, you are right. I just hope that the system you know does not encode
2000-01-01 11:59:59Z = (time_t) -1
as this value is reserved by the standard for error conditions.
A problematical situation on any implementation is distinguishing between an error return from mktime() and mktime() returning a legitimate -1 value. Another unpleasantness of the API. But this is the only place besides time() where the C standard has a function returning a time_t, and time() is not defined to have an error return. --Ken Pizzini
¤ Comparing t with 0 doesn't take any sense (I know one system where ¤ (time_t)0 is J2000,0, so negative t are allowed before 2000-01-01 12:00:00Z
Ok, you are right. I just hope that the system you know does not encode
2000-01-01 11:59:59Z = (time_t) -1
as this value is reserved by the standard for error conditions.
A problematical situation on any implementation is distinguishing between an error return from mktime() and mktime() returning a legitimate -1 value. Another unpleasantness of the API. But this is the only place besides time() where the C standard has a function returning a time_t, and time() is not defined to have an error return.
An error code (or errno) would help here I think. If errno were set to a particular value when mktime() really couldn't represent the value, we'd have a way to distinguish between a valid -1 and and error -1 return value. Problem is, we'd have trouble getting the standards like X/Open to accept this, since they claim they don't support negative time_t's (ie: times before the Epoch). - Tom
participants (4)
-
guy@netapp.com -
Ken Pizzini -
kuhn@cs.purdue.edu -
Tom Peterson