Writing code that deals with time values
Writing code that deals with time values
- Subject: Writing code that deals with time values
- From: Terry Lambert <email@hidden>
- Date: Fri, 25 Apr 2008 16:23:50 -0700
This will be my last posting on this topic.
--
Here is a short primer for people interested in writing working code:
Q: I want to use arbitrary dates on Mac OS X
A: Use NSDate/CFDate
Q: But I want my code to be portable between Linux, Mac OS X, and
other UNIX operating systems; what interfaces can I use?
A: You can use the POSIX C library functions and you can use the POSIX
system functions, as long as you are aware of natural type
restrictions and what POSIX does or doesn't guarantee in terms of
implementation details
Q: What are the natural types used by the POSIX C library functions?
A: The POSIX C library functions use a mix of struct tm, struct
timespec, struct timeval, and time_t
Q: What are the natural types used by the POSIX system functions?
A: The POSIX system functions use a mix of struct timespec, struct
timeval, and time_t
Q: What is the lowest common denominator - the "natural" type - for
time values on POSIX systems?
A: time_t, which is a signed value in seconds relative to the UNIX
Epoch of January 1st 1970
Q: What are the restrictions on date ranges are supported by these
types?
A: It depends on the type, and whether the system is 32 or 64 bit:
32 bit time_t Jan 1 1970 00:00 +/- 2^31 seconds (Y1902 - Y2038)
64 bit time_t Y1970 +/- 2^63 seconds (~ +/- 209 billion years)
struct timespec same as time_t
struct timeval same as time_t
struct tm Y1900 +/- 2^31 years (~ +/- 2 billion years)
Q: Doesn't that mean that there's potentially a problem for UNIX
systems around Y2038?
A: Yes. Computer scientists are aware of the issue, and have known
about it for many years. There is even a Wikipedia article on it.
Q: So if I am using POSIX interfaces, I should use a 64 bit time_t or
struct tm to represent large date ranges?
A: struct tm *can* represent large date ranges, but conversion is
ambiguous; use a 64 bit time_t where possible to avoid the ambiguity.
Q: What if I don't want to use a 64 bit time_t , can I use a struct tm
instead?
A: Either limit the ranges in which your software is going to operate,
or carry around your own functions; the POSIX C library function
conversions are ambiguous; it's impossible to use struct tm and get
consistent cross-platform results
Q: Why?
A: The POSIX interfaces which deal with struct tm, as specified, lack
reflexivity under certain conditions.
Q: What does that mean?
A: There is no function to get the current time without conversion
from a time_t, and the range of the conversion into and out of time_t
is bounded by the range bounds on time_t, and some of the functions
are inconsistent or insufficiently specific. This translates to not
being able to trust the conversion routines in a couple of cases.
Q: What if I disagree with the Mac OS X interpretation of a standards
ambiguity?
A: File a bug.
Q: What are the ambiguous cases?
A: You can't trust the conversion routines to be able to be called to
convert, and then convert back a value, and give the original input
back to you. This is both because some values you could put in a
struct tm can't fit into a time_t (as an internal implementation
detail), and because some of the conversion routines don't specify an
Epoch date (strftime(3)). Also, because there is no method of
obtaining the current time that doesn't transit a system interface,
there's no way to get the current time as anything other than a time_t
value.
Q: So I can't get the current time as a struct tm?
A: No. Not without calling one of gmtime(3), gmtime_r(3),
localtime(3), or localtime_r(3) on the results of a call to time(2),
which only returns a time_t.
Q: So my code will always have the Y2038 bug?
A: No. You can compile your code as 64 bit, which will give you a 64
bit time_t; this will prevent having the Y2038 bug.
Q: How do I avoid POSIX interface ambiguity?
A: Start by using 4 byte year+century fields instead of 2 byte year-
within-century fields; avoid %y and %C as separate formatting
characters. If you insist on using these format specifiers, the best
you can achieve is changing your T2038 bug into a Y2069 bug instead,
assuming you never care about the current time after Y2038.
Q: What's the bottom line, if time_t is 32 bits on my system?
A: Your code has the Y2038 bug, if it deals with the current time or
does math on time using standard functions, such as difftime(3).
Q: Are there any other alternatives?
A: Yes. Carry around your own private non-POSIX date manipulation
functions as part of your software. This will make your code behave
consistently on all platforms.
-- Terry
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden