[comp.std.c] ANSI C date & time library functions.

dave@moncam.co.uk (Speaker-To-Animals) (02/06/90)

I am writing an implementation of the ANSI C date and time functions.
Unfortunately, I don't have a copy of the standard itself yet, so I'm
working from K&R2.  time_t is described as a scalar type.  difftime() returns
the difference between two times as a double.  If time_t represents a time
in centiseconds (say), a 32-bit unsigned value will cover a period of a year
or so.  Are times more precise than 1 second only possible in implementations 
with greater than 32 bit integers?  Since time() returns -1 if the time is
not available, it doesn't seem possible to define time_t as an array of
integers.
--
Dave Allen
Monotype International ADG
Science Park
Milton Road
Cambridge CB4 4FQ
England

dave@moncam.UUCP

henry@utzoo.uucp (Henry Spencer) (02/10/90)

In article <DAVE.90Feb6112502@marvin.moncam.co.uk> dave@moncam.co.uk (Speaker-To-Animals) writes:
>... time_t is described as a scalar type.  difftime() returns
>the difference between two times as a double.  If time_t represents a time
>in centiseconds (say), a 32-bit unsigned value will cover a period of a year
>or so.  Are times more precise than 1 second only possible in implementations 
>with greater than 32 bit integers?  Since time() returns -1 if the time is
>not available, it doesn't seem possible to define time_t as an array of
>integers.

Unless this changed since the Oct 88 draft, time_t is not constrained to
be a scalar type, only to be an arithmetic type.  That is, it could be
floating-point.  It also might be some implementation-specific type like
"long long int".  Furthermore, there is no guarantee that you can do
useful arithmetic on time_t values; the encoding of the time in a time_t
is explicitly unspecified, the only constraint being that `(time_t) -1'
must not be a valid time.  The inability to do arithmetic is the reason
why difftime() exists.

You are correct that a 32-bit integer isn't practical for time resolutions
less than one second; indeed, it's increasingly marginal even at that
resolution, since the times "go negative" less than fifty years from now.
I'd say time_t is going to have to go to 64 bits (or perhaps to floating
point) fairly soon.
-- 
SVR4:  every feature you ever |     Henry Spencer at U of Toronto Zoology
wanted, and plenty you didn't.| uunet!attcan!utzoo!henry henry@zoo.toronto.edu

karl@haddock.ima.isc.com (Karl Heuer) (02/10/90)

In article <1990Feb9.183316.24925@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes:
>In article <DAVE.90Feb6112502@marvin.moncam.co.uk> dave@moncam.co.uk (Speaker-To-Animals) writes:
>>Are times more precise than 1 second only possible in implementations
>>with greater than 32 bit integers?
>
>... [time_t] could be floating-point.

>You are correct that a 32-bit integer isn't practical for time resolutions
>less than one second; indeed, it's increasingly marginal even at that
>resolution, since the times "go negative" less than fifty years from now.
>I'd say time_t is going to have to go to 64 bits (or perhaps to floating
>point) fairly soon.

Not necessarily.  An unsigned long would give us 32 bits (worst case) instead
of the current 31; this would push the "overflow date" into the 22nd century.
The need for sub-second resolution is the dominant requirement here.

As far as I can see, the only reason that it has to be arithmetic at all is so
that time() can return (time_t)-1 to flag an error.  This is rather bizarre,
since existing Unix implementations never return an error from time();
unfortunately, because existing code uses "t = time((time_t *)0);" in addition
to the equivalent "(void)time(&t);" to read the time, it appears that there
wasn't much choice.  I wonder if maybe "time()" should have been deprecated in
favor of a "gettime()" function that would only return 0 (filling in its
argument like time() does) or -1.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint

flee@shire.cs.psu.edu (Felix Lee) (02/10/90)

Are you allowed to compare time_ts without using difftime()?  Or
should I write "difftime(now, then) < 0" instead of "now < then"?

Can time_t be a pointer (converted to an arithmetic if necessary)?
Imagine
	typedef struct tm * time_t;
time() would allocate a new struct tm and return a pointer to it.
This is assuming you don't compare time_t values directly and don't
try to read or write them.
--
Felix Lee	flee@shire.cs.psu.edu	*!psuvax1!flee

bdm659@csc.anu.oz (02/10/90)

In article <1990Feb9.183316.24925@utzoo.uucp>, henry@utzoo.uucp (Henry Spencer) writes:
>
> Unless this changed since the Oct 88 draft, time_t is not constrained to
> be a scalar type, only to be an arithmetic type.  That is, it could be
> floating-point.

It's the same in the Dec 1988 draft.

>                  It also might be some implementation-specific type like
> "long long int".

Are you sure about that?  Section 3.1.2.5 claims to give a complete list
of arithmetic types.  Shouldn't we take "arithmetic type" as meaning "one
of the types this Standard says are arithmetic types"?  I can't find any
specific guidelines on this matter in the Standard, though Section 3.3.3.4
of the Rationale has this to say about the size_t type:
    "The type of sizeof, whatever it is, is published (in the library
     header <stddef.h>) as size_t, since it is useful for the programmer
     to be able to refer to this type.  This requirement implicitly
     restricts size_t to be a synonym for an *existing* unsigned integer
     type, thus quashing any notion that the largest declarable object
     might be too big to span even with an unsigned long."  [my emphasis]

Brendan McKay.  bdm@anucsd.oz(.au)  or bdm659@csc1.anu.oz(.au)
terrorist: n. an individual who behaves like a government

henry@utzoo.uucp (Henry Spencer) (02/11/90)

In article <15919@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>>[32-bit time_t] times "go negative" less than fifty years from now...
>
>Not necessarily.  An unsigned long would give us 32 bits (worst case) instead
>of the current 31; this would push the "overflow date" into the 22nd century.

Unfortunately, there's a major backward-compatibility issue here:  all the
Unix code which assumes that the difference of two time_t values is signed.
Yes, that code "really ought to" use difftime() to avoid this, and not doing
so limits its portability... but declaring it unportable is one thing, and
breaking it even in its native environment is another.  I don't think it's
worth the trouble for one bit.  We need a longer-term solution which also
(as Karl points out) addresses the issue of better resolution.

>...the only reason that it has to be arithmetic at all is so
>that time() can return (time_t)-1 to flag an error.  This is rather bizarre,
>since existing Unix implementations never return an error from time()...

However, non-Unix implementations may have to, if they can't supply a time.
-- 
SVR4:  every feature you ever |     Henry Spencer at U of Toronto Zoology
wanted, and plenty you didn't.| uunet!attcan!utzoo!henry henry@zoo.toronto.edu

henry@utzoo.uucp (Henry Spencer) (02/11/90)

In article <Ccvioy2@cs.psu.edu> flee@shire.cs.psu.edu (Felix Lee) writes:
>Are you allowed to compare time_ts without using difftime()?  Or
>should I write "difftime(now, then) < 0" instead of "now < then"?

There is explicitly no guarantee of the internal representation of time_t.
Since it is an arithmetic type, you can do direct comparisons... but there
is no guarantee that the result will be meaningful.  If you want portable
comparisons, difftime() is indeed the correct method.

>Can time_t be a pointer (converted to an arithmetic if necessary)?
>...This is assuming you don't compare time_t values directly and don't
>try to read or write them.

Unfortunately, there is way too much existing code which assumes that
a time_t can be assigned, passed around, etc.  A pointer is not an
arithmetic type and hence is not a legal time_t type.
-- 
SVR4:  every feature you ever |     Henry Spencer at U of Toronto Zoology
wanted, and plenty you didn't.| uunet!attcan!utzoo!henry henry@zoo.toronto.edu

henry@utzoo.uucp (Henry Spencer) (02/11/90)

In article <1487.25d42437@csc.anu.oz> bdm659@csc.anu.oz writes:
>>                  It also might be some implementation-specific type like
>> "long long int".
>
>Are you sure about that? ...

No.  Slippery area.
-- 
SVR4:  every feature you ever |     Henry Spencer at U of Toronto Zoology
wanted, and plenty you didn't.| uunet!attcan!utzoo!henry henry@zoo.toronto.edu

gwc@root.co.uk (Geoff Clare) (02/13/90)

In article <15919@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>As far as I can see, the only reason that it has to be arithmetic at all is so
>that time() can return (time_t)-1 to flag an error.  This is rather bizarre,
>since existing Unix implementations never return an error from time();

It's needed so that mktime() can return (time_t)-1 to flag an error (for
unrepresentable times).
-- 
Geoff Clare, UniSoft Limited, Saunderson House, Hayne Street, London EC1A 9HH
gwc@root.co.uk  (Dumb mailers: ...!uunet!root.co.uk!gwc)  Tel: +44-1-315-6600
                                         (from 6th May 1990): +44-71-315-6600