Y2038 and time_t

  • Follow


With time_t being a signed 32 bit integer marking the number of seconds
since 1 Jan 1970, most of us know it will be overflowing on 19 Jan 2038
(6 Jan 2038 if you use the Julian calendar).  So how will this end up
being fixed?  I see some possibilities:

1.  Redefine time_t to be a 64 bit signed integer.  This would be way
overkill since it is more than enough to measure the time until our star
is projected to die.  There's also no standard way to check for largest
possible value as a constant (as in INT_MAX for type int) so code can work
in either environment right now.

2.  Change the units on time_t from 1 second to 2 seconds or more.  This
could get us to 7 Feb 2106 or beyond, but at the cost of breaking a lot of
code along the way.

3.  Change time_t to 64 bits AND change the units to nanoseconds.  This
would be a versatile number.  It would get us to 11 Apr 2262 while at the
same time be a number that could be used for fine resolution.  But it,
too, would break code that assumes time_t is exactly one second steps.

4.  Use a completely new type and depricate time_t.  Maybe longtime_t? 
But this is like sweeping the problem under the rug.

5.  Switch from signed 32 bits to unsigned 32 bits.  That means trading
off the ability to calculate time before 1970 for the ability to calculate
time beyond 2038.  I'm sure something will break.

So what will be done?  Or what do you think should be done?

If this will require changes in code to make code that is portably Y2038
compliant (methods 1 and 5 would not break any of my code) I'd like to
start using that method now.

-- 
-----------------------------------------------------------------------------
| Phil Howard KA9WGN       | http://linuxhomepage.com/      http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/   http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
0
Reply phil 3/31/2006 10:04:50 PM

phil-news-nospam@ipal.net writes:

>1.  Redefine time_t to be a 64 bit signed integer.  This would be way
>overkill since it is more than enough to measure the time until our star
>is projected to die.  There's also no standard way to check for largest
>possible value as a constant (as in INT_MAX for type int) so code can work
>in either environment right now.

That's what the bulk of 64 bit Unix variants use.

Will 32 bit binaries have died in 2038?

Casper
0
Reply Casper 3/31/2006 10:28:34 PM


phil-news-nospam@ipal.net writes:
> With time_t being a signed 32 bit integer marking the number of seconds
> since 1 Jan 1970, most of us know it will be overflowing on 19 Jan 2038
> (6 Jan 2038 if you use the Julian calendar).  So how will this end up
> being fixed?  I see some possibilities:
>
> 1.  Redefine time_t to be a 64 bit signed integer.  This would be way
> overkill since it is more than enough to measure the time until our star
> is projected to die.  There's also no standard way to check for largest
> possible value as a constant (as in INT_MAX for type int) so code can work
> in either environment right now.

The C standard only requires time_t to be an arithmetic type capable
of representing times.  There's no statement about the resolution; it
needn't even be linear or monotonic.

I'm not sure what POSIX requires, but I'm failure sure it allows it to
be more than 32 bits.

Many current 64-bit systems implement time_t as a signed 64-bit
integer type representing seconds since 1970-01-01 00:00:00.  The
current C standard, C99 requires support for at least 64-bit integers,
so making time_t 64 bits even on 32-bit systems would be reasonable.

time_t 2**31-1 is nearly 32 years away.  By the time we get there, I
suspect that 32-bit time_t will be obsolete.  There's no need to
introduce incompatible changes.  (And if there is, I suggest waiting
at least 10 years before deciding.)

(There may be problems before then representing future times.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
San Diego Supercomputer Center             <*>  <http://users.sdsc.edu/~kst>
We must do something.  This is something.  Therefore, we must do this.
0
Reply Keith 3/31/2006 10:46:09 PM

On Fri, 31 Mar 2006 22:46:09 GMT Keith Thompson <kst-u@mib.org> wrote:
| phil-news-nospam@ipal.net writes:
|> With time_t being a signed 32 bit integer marking the number of seconds
|> since 1 Jan 1970, most of us know it will be overflowing on 19 Jan 2038
|> (6 Jan 2038 if you use the Julian calendar).  So how will this end up
|> being fixed?  I see some possibilities:
|>
|> 1.  Redefine time_t to be a 64 bit signed integer.  This would be way
|> overkill since it is more than enough to measure the time until our star
|> is projected to die.  There's also no standard way to check for largest
|> possible value as a constant (as in INT_MAX for type int) so code can work
|> in either environment right now.
| 
| The C standard only requires time_t to be an arithmetic type capable
| of representing times.  There's no statement about the resolution; it
| needn't even be linear or monotonic.
| 
| I'm not sure what POSIX requires, but I'm failure sure it allows it to
| be more than 32 bits.

I do believe it specifies, or at least implies, 1 second resolution.
That wouldn't contradict the C standard; just narrow it.  Programs
written to Standard C should work in POSIX.  Programs written to POSIX
are not expected to work in all Standard C environments.


| Many current 64-bit systems implement time_t as a signed 64-bit
| integer type representing seconds since 1970-01-01 00:00:00.  The
| current C standard, C99 requires support for at least 64-bit integers,
| so making time_t 64 bits even on 32-bit systems would be reasonable.

I'd agree that it would work.  I'm not sure that's the best, but it
may be all we have within the constraint of maximum portability.


| time_t 2**31-1 is nearly 32 years away.  By the time we get there, I
| suspect that 32-bit time_t will be obsolete.  There's no need to
| introduce incompatible changes.  (And if there is, I suggest waiting
| at least 10 years before deciding.)
| 
| (There may be problems before then representing future times.)

There are indeed problems representing future times.  Y2K had some issues
like that well before 1 Jan 2000, some cropping up as early as the 1970's.
FYI, Bob Bemer did warn us about this in the 1960's.

One aspect of this is that the C Standard Library tools for dates is an
attractive tool to use because it is so standard and widespread.  It can
be tempting to use it in applications that need to compute future and
past times, regardless of system times.  The sooner we make time_t handle
a much wider range (at least maximum life span of a human who is either
ending or beginning that life span today), the sooner we get past the
troubles of people using that.

Otherwise we need a portable date calculation tool that is independent of
POSIX time_t.

Isn't one of the intentions of giving applicational types like time_t
their own name so that they can be changed when needed and just recompile?
Yes, I know many programs come in binary; but that's the vendor's issue.

I have written my own set of time calculation tools (which can be gotten
at http://libh.slashusr.org/ ) that do not have Y2.038K limits except with
respect to using time_t from the system on 32 bit machines.  Since I did
want to correctly test for conversion to time_t going out of bounds, I do
need the actual limit values (portably).  What I have done before is:

#define TIME_MIN (((time_t)1)<<(((sizeof(time_t))*(CHAR_BIT))-1))
#define TIME_MAX (~(((time_t)1)<<(((sizeof(time_t))*(CHAR_BIT))-1)))

Later I generalized the problem with the macros shown in the code below.
Even with -O0 gcc completely evaluates these entirely constant expressions
to a final value at compile time.  Maybe someone can test this on a 64-bit
machine and see what it produces.  I don't know how far back in gcc versions
this holds true.  I do suspect (hope) all decent C compilers will do this.

These macros are taken from LIBH under GPL licensing:

=============================================================================
phil@canopus:/home/phil 891> cat timetest.c
#include <limits.h>
#include <time.h>

#define type_bits(t) ( sizeof(t) * (CHAR_BIT) )
#define int_is_signed(t) ( ( ( (t)( ((t)0) - ((t)1) ) ) < ((t)0) ) ? 1 : 0 )
#define int_is_unsigned(t) ( ( ( (t)( ((t)0) - ((t)1) ) ) < ((t)0) ) ? 0 : 1 )
#define sint_max(t) ( (t) ( ~ ( (t) ( ( (t) 1 ) << ( type_bits(t) - 1 ) ) ) ) )
#define sint_min(t) ( (t) ( ( (t) 1 ) << ( type_bits(t) - 1 ) ) )
#define uint_max(t) ( (t) ~ ( (t) 0 ) )
#define uint_min(t) ( (t) 0 )
#define int_min(t) ( int_is_signed(t) ? sint_min(t) : uint_min(t) )
#define int_max(t) ( (t) ~ int_min(t) )
#define TIME_MAX int_max( time_t )
#define TIME_MIN int_min( time_t )

time_t get_time_max()
{
    return TIME_MAX;
}

time_t get_time_min()
{
    return TIME_MIN;
}

phil@canopus:/home/phil 892> gcc -O0 -S -o timetest.s timetest.c
phil@canopus:/home/phil 893> cat timetest.s
        .file   "timetest.c"
        .text
..globl get_time_max
        .type   get_time_max, @function
get_time_max:
        pushl   %ebp
        movl    %esp, %ebp
        movl    $2147483647, %eax
        popl    %ebp
        ret
        .size   get_time_max, .-get_time_max
..globl get_time_min
        .type   get_time_min, @function
get_time_min:
        pushl   %ebp
        movl    %esp, %ebp
        movl    $-2147483648, %eax
        popl    %ebp
        ret
        .size   get_time_min, .-get_time_min
        .section        .note.GNU-stack,"",@progbits
        .ident  "GCC: (GNU) 3.3.6"
phil@canopus:/home/phil 894>
=============================================================================


Oh wait, I still have an old machine with an old gcc ... let's see:

=============================================================================
phil@dubhe:/home/phil 49> gcc -O0 -S -o timetest.s timetest.c
phil@dubhe:/home/phil 50> cat timetest.s
        .file   "timetest.c"
        .version        "01.01"
gcc2_compiled.:
..text
        .align 4
..globl get_time_max
        .type    get_time_max,@function
get_time_max:
        pushl %ebp
        movl %esp,%ebp
        movl $2147483647,%eax
        jmp .L2
        .p2align 4,,7
..L2:
        leave
        ret
..Lfe1:
        .size    get_time_max,.Lfe1-get_time_max
        .align 4
..globl get_time_min
        .type    get_time_min,@function
get_time_min:
        pushl %ebp
        movl %esp,%ebp
        movl $-2147483648,%eax
        jmp .L3
        .p2align 4,,7
..L3:
        leave
        ret
..Lfe2:
        .size    get_time_min,.Lfe2-get_time_min
        .ident  "GCC: (GNU) 2.95.3 20010315 (release)"
phil@dubhe:/home/phil 51>
=============================================================================

It isn't that hard to evaluate a parse tree of constants, so despite how
complex that bunch of macros is, it works fine to yield the minimum and
maximum value of a given integer type such as time_t.

-- 
-----------------------------------------------------------------------------
| Phil Howard KA9WGN       | http://linuxhomepage.com/      http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/   http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
0
Reply phil 4/4/2006 8:33:11 PM

phil-news-nospam@ipal.net writes:
> On Fri, 31 Mar 2006 22:46:09 GMT Keith Thompson <kst-u@mib.org> wrote:
> | phil-news-nospam@ipal.net writes:
> |> With time_t being a signed 32 bit integer marking the number of seconds
> |> since 1 Jan 1970, most of us know it will be overflowing on 19 Jan 2038
> |> (6 Jan 2038 if you use the Julian calendar).  So how will this end up
> |> being fixed?  I see some possibilities:
> |>
> |> 1.  Redefine time_t to be a 64 bit signed integer.  This would be way
> |> overkill since it is more than enough to measure the time until our star
> |> is projected to die.  There's also no standard way to check for largest
> |> possible value as a constant (as in INT_MAX for type int) so code can work
> |> in either environment right now.
> | 
> | The C standard only requires time_t to be an arithmetic type capable
> | of representing times.  There's no statement about the resolution; it
> | needn't even be linear or monotonic.
> | 
> | I'm not sure what POSIX requires, but I'm failure sure it allows it to
> | be more than 32 bits.

I mean "fairly sure", of course.

> I do believe it specifies, or at least implies, 1 second resolution.
> That wouldn't contradict the C standard; just narrow it.  Programs
> written to Standard C should work in POSIX.  Programs written to POSIX
> are not expected to work in all Standard C environments.

Right.

[...]

> I have written my own set of time calculation tools (which can be gotten
> at http://libh.slashusr.org/ ) that do not have Y2.038K limits except with
> respect to using time_t from the system on 32 bit machines.  Since I did
> want to correctly test for conversion to time_t going out of bounds, I do
> need the actual limit values (portably).  What I have done before is:
>
> #define TIME_MIN (((time_t)1)<<(((sizeof(time_t))*(CHAR_BIT))-1))
> #define TIME_MAX (~(((time_t)1)<<(((sizeof(time_t))*(CHAR_BIT))-1)))

Which assumes (1) that time_t is a signed integer type and (2) that it
has no padding bits.

> Later I generalized the problem with the macros shown in the code below.
> Even with -O0 gcc completely evaluates these entirely constant expressions
> to a final value at compile time.  Maybe someone can test this on a 64-bit
> machine and see what it produces.  I don't know how far back in gcc versions
> this holds true.  I do suspect (hope) all decent C compilers will do this.
>
> These macros are taken from LIBH under GPL licensing:
>
> =============================================================================
> phil@canopus:/home/phil 891> cat timetest.c
> #include <limits.h>
> #include <time.h>
>
> #define type_bits(t) ( sizeof(t) * (CHAR_BIT) )
> #define int_is_signed(t) ( ( ( (t)( ((t)0) - ((t)1) ) ) < ((t)0) ) ? 1 : 0 )
> #define int_is_unsigned(t) ( ( ( (t)( ((t)0) - ((t)1) ) ) < ((t)0) ) ? 0 : 1 )
> #define sint_max(t) ( (t) ( ~ ( (t) ( ( (t) 1 ) << ( type_bits(t) - 1 ) ) ) ) )
> #define sint_min(t) ( (t) ( ( (t) 1 ) << ( type_bits(t) - 1 ) ) )
> #define uint_max(t) ( (t) ~ ( (t) 0 ) )
> #define uint_min(t) ( (t) 0 )
> #define int_min(t) ( int_is_signed(t) ? sint_min(t) : uint_min(t) )
> #define int_max(t) ( (t) ~ int_min(t) )
> #define TIME_MAX int_max( time_t )
> #define TIME_MIN int_min( time_t )
>
> time_t get_time_max()
> {
>     return TIME_MAX;
> }
>
> time_t get_time_min()
> {
>     return TIME_MIN;
> }

[snip]

I tried this on several 64-bit Linux machines (x86_64, ia64, ppc64).
In all cases, the code for the get_time_max and get_time_min functions
appeared to be the same as if an integer literal were used rather than
a macro expansion.  (It's a little more complicated on the ppc64, but
it's still equivalent to the code generated for a literal.)

Since the C standard requires the compiler to be able to evaluate
constant expressions in many cases, it's not surprising that it's able
to do so.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
San Diego Supercomputer Center             <*>  <http://users.sdsc.edu/~kst>
We must do something.  This is something.  Therefore, we must do this.
0
Reply Keith 4/4/2006 9:36:10 PM

On Tue, 04 Apr 2006 21:36:10 GMT Keith Thompson <kst-u@mib.org> wrote:
| phil-news-nospam@ipal.net writes:
|> On Fri, 31 Mar 2006 22:46:09 GMT Keith Thompson <kst-u@mib.org> wrote:
|> | phil-news-nospam@ipal.net writes:
|> |> With time_t being a signed 32 bit integer marking the number of seconds
|> |> since 1 Jan 1970, most of us know it will be overflowing on 19 Jan 2038
|> |> (6 Jan 2038 if you use the Julian calendar).  So how will this end up
|> |> being fixed?  I see some possibilities:
|> |>
|> |> 1.  Redefine time_t to be a 64 bit signed integer.  This would be way
|> |> overkill since it is more than enough to measure the time until our star
|> |> is projected to die.  There's also no standard way to check for largest
|> |> possible value as a constant (as in INT_MAX for type int) so code can work
|> |> in either environment right now.
|> | 
|> | The C standard only requires time_t to be an arithmetic type capable
|> | of representing times.  There's no statement about the resolution; it
|> | needn't even be linear or monotonic.
|> | 
|> | I'm not sure what POSIX requires, but I'm failure sure it allows it to
|> | be more than 32 bits.
| 
| I mean "fairly sure", of course.

It most certainly allows it.  The issue is making the transition.  If a
binary program is getting the time in 32 bit form, and the OS provides it
in 64 bit form, it won't work.  The ABI has to match.

We can make time() and gettimeofday() be 64 bit (the tv_sec field in
struct timeval for the gettimeofday() function) right now.  But look at
what breaks as soon as you do that ... programs already compiled to use
32 bits.


|> I have written my own set of time calculation tools (which can be gotten
|> at http://libh.slashusr.org/ ) that do not have Y2.038K limits except with
|> respect to using time_t from the system on 32 bit machines.  Since I did
|> want to correctly test for conversion to time_t going out of bounds, I do
|> need the actual limit values (portably).  What I have done before is:
|>
|> #define TIME_MIN (((time_t)1)<<(((sizeof(time_t))*(CHAR_BIT))-1))
|> #define TIME_MAX (~(((time_t)1)<<(((sizeof(time_t))*(CHAR_BIT))-1)))
| 
| Which assumes (1) that time_t is a signed integer type and (2) that it
| has no padding bits.

I'd say (2) was a relatively safe assumption.  I'm basically concerned what
is the smallest and largest I can get in there so I know whether conversion
to time_t is valid for a given value in another time repreentation that is
going to be well beyond time_t in its 32-bit form.


|> Later I generalized the problem with the macros shown in the code below.
|> Even with -O0 gcc completely evaluates these entirely constant expressions
|> to a final value at compile time.  Maybe someone can test this on a 64-bit
|> machine and see what it produces.  I don't know how far back in gcc versions
|> this holds true.  I do suspect (hope) all decent C compilers will do this.
|>
|> These macros are taken from LIBH under GPL licensing:
|>
|> =============================================================================
|> phil@canopus:/home/phil 891> cat timetest.c
|> #include <limits.h>
|> #include <time.h>
|>
|> #define type_bits(t) ( sizeof(t) * (CHAR_BIT) )
|> #define int_is_signed(t) ( ( ( (t)( ((t)0) - ((t)1) ) ) < ((t)0) ) ? 1 : 0 )
|> #define int_is_unsigned(t) ( ( ( (t)( ((t)0) - ((t)1) ) ) < ((t)0) ) ? 0 : 1 )
|> #define sint_max(t) ( (t) ( ~ ( (t) ( ( (t) 1 ) << ( type_bits(t) - 1 ) ) ) ) )
|> #define sint_min(t) ( (t) ( ( (t) 1 ) << ( type_bits(t) - 1 ) ) )
|> #define uint_max(t) ( (t) ~ ( (t) 0 ) )
|> #define uint_min(t) ( (t) 0 )
|> #define int_min(t) ( int_is_signed(t) ? sint_min(t) : uint_min(t) )
|> #define int_max(t) ( (t) ~ int_min(t) )
|> #define TIME_MAX int_max( time_t )
|> #define TIME_MIN int_min( time_t )
|>
|> time_t get_time_max()
|> {
|>     return TIME_MAX;
|> }
|>
|> time_t get_time_min()
|> {
|>     return TIME_MIN;
|> }
| 
| [snip]
| 
| I tried this on several 64-bit Linux machines (x86_64, ia64, ppc64).
| In all cases, the code for the get_time_max and get_time_min functions
| appeared to be the same as if an integer literal were used rather than
| a macro expansion.  (It's a little more complicated on the ppc64, but
| it's still equivalent to the code generated for a literal.)

The PPC will load a literal in a few small chunks.  No big deal.

But at least the above method is no longer assuming time_t is signed.

-- 
-----------------------------------------------------------------------------
| Phil Howard KA9WGN       | http://linuxhomepage.com/      http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/   http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
0
Reply phil 4/5/2006 5:59:37 AM

phil-news-nospam@ipal.net writes:

>It most certainly allows it.  The issue is making the transition.  If a
>binary program is getting the time in 32 bit form, and the OS provides it
>in 64 bit form, it won't work.  The ABI has to match.

We've already started the transition in some way: 64 bit OSes allow for
64 bit applications which use 64 bit timestamps.

>We can make time() and gettimeofday() be 64 bit (the tv_sec field in
>struct timeval for the gettimeofday() function) right now.  But look at
>what breaks as soon as you do that ... programs already compiled to use
>32 bits.

Yes, you would need to rev the 32 bit ABI.  Since that is a porting
project, you can just as well skip and go to 64 bits directly.

Casper
-- 
Expressed in this posting are my opinions.  They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
0
Reply Casper 4/5/2006 8:03:14 AM

phil-news-nospam@ipal.net writes:
> On Tue, 04 Apr 2006 21:36:10 GMT Keith Thompson <kst-u@mib.org> wrote:
> | phil-news-nospam@ipal.net writes:
> |> On Fri, 31 Mar 2006 22:46:09 GMT Keith Thompson <kst-u@mib.org> wrote:
[...]
> |> | The C standard only requires time_t to be an arithmetic type capable
> |> | of representing times.  There's no statement about the resolution; it
> |> | needn't even be linear or monotonic.
> |> | 
> |> | I'm not sure what POSIX requires, but I'm failure sure it allows it to
> |> | be more than 32 bits.
> | 
> | I mean "fairly sure", of course.
>
> It most certainly allows it.  The issue is making the transition.  If a
> binary program is getting the time in 32 bit form, and the OS provides it
> in 64 bit form, it won't work.  The ABI has to match.
>
> We can make time() and gettimeofday() be 64 bit (the tv_sec field in
> struct timeval for the gettimeofday() function) right now.  But look at
> what breaks as soon as you do that ... programs already compiled to use
> 32 bits.

Not necessarily:

% uname -mo
x86_64 GNU/Linux
% gcc -dumpversion
3.4.3
% cat time_test.c
#include <time.h>
#include <stdio.h>
#include <limits.h>
int main(void)
{
    time_t now = time(NULL);
    printf("now = %ld, time_t is %d bits\n",
           (unsigned long)now,
           (int)(CHAR_BIT * sizeof(time_t)));
    return 0;
} 
% gcc -m32 time_test.c -o time_test && ./time_test
now = 1144229533, time_t is 32 bits
% gcc -m64 time_test.c -o time_test && ./time_test
now = 1144229541, time_t is 64 bits

It works by using two sets of libraries.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
San Diego Supercomputer Center             <*>  <http://users.sdsc.edu/~kst>
We must do something.  This is something.  Therefore, we must do this.
0
Reply Keith 4/5/2006 9:41:54 AM

>With time_t being a signed 32 bit integer marking the number of seconds
>since 1 Jan 1970, most of us know it will be overflowing on 19 Jan 2038
>(6 Jan 2038 if you use the Julian calendar).  So how will this end up
>being fixed?  I see some possibilities:

C does not require a time_t to even be a "number of <something> since
<epoch>".  And there's no specific size for it (or any other type
in C - minimum number of bits, yes, specific size, no).  For example,
to convert to time_t, you could write down the date in the form 
HHMMSSDDMMYYYYYY, treat the result as a decimal number, and convert
to binary.  That mess isn't even monotonic.

>1.  Redefine time_t to be a 64 bit signed integer.  This would be way
>overkill since it is more than enough to measure the time until our star
>is projected to die.  There's also no standard way to check for largest
>possible value as a constant (as in INT_MAX for type int) so code can work
>in either environment right now.

I think #1 is what's going to happen.

I would prefer (variant of #3) to redefine time_t to be a 256 bit
signed integer as the number of yoctoseconds (10**-24 seconds) since
the beginning of the universe.  Slight problem here:  we don't know
when that was to any accuracy.  And it violates POSIX requirements
for a time_t being in seconds.

Oh, yes, while we're at it, and to create problems for the future,
change tm_year to be a signed 128-bit integer, minimum.

>2.  Change the units on time_t from 1 second to 2 seconds or more.  This
>could get us to 7 Feb 2106 or beyond, but at the cost of breaking a lot of
>code along the way.

That's going to break a heck of a lot of code.  Especially the part about
not being able to represent times with odd seconds.

>3.  Change time_t to 64 bits AND change the units to nanoseconds.  This
>would be a versatile number.  It would get us to 11 Apr 2262 while at the
>same time be a number that could be used for fine resolution.  But it,
>too, would break code that assumes time_t is exactly one second steps.

Unfortunately, POSIX assumes that.

>4.  Use a completely new type and depricate time_t.  Maybe longtime_t? 
>But this is like sweeping the problem under the rug.

I'm not sure it is if the new time representation has a sufficient
number of bits.

>5.  Switch from signed 32 bits to unsigned 32 bits.  That means trading
>off the ability to calculate time before 1970 for the ability to calculate
>time beyond 2038.  I'm sure something will break.

I believe some systems already have an unsigned time_t.

>So what will be done?  Or what do you think should be done?
>
>If this will require changes in code to make code that is portably Y2038
>compliant (methods 1 and 5 would not break any of my code) I'd like to
>start using that method now.

I think what will happen is #1.

						Gordon L. Burditt
0
Reply gordonb 4/5/2006 10:02:05 AM

On 05 Apr 2006 08:03:14 GMT Casper H.S. Dik <Casper.Dik@sun.com> wrote:
| phil-news-nospam@ipal.net writes:
| 
|>It most certainly allows it.  The issue is making the transition.  If a
|>binary program is getting the time in 32 bit form, and the OS provides it
|>in 64 bit form, it won't work.  The ABI has to match.
| 
| We've already started the transition in some way: 64 bit OSes allow for
| 64 bit applications which use 64 bit timestamps.

But that leaves 32 bit OSes ... which already have quite a number of 64
bit interfacing as it is, just not for time() or gettimeofday() out in
the cold.

Will 32 bit OSes still be around in 2038?  I think the better question is
will we need to calculate beyond 2038 while 32 bit OSes are still here.

Hosted machines will mostly all be 64 bit or maybe even 128 but by 2038.
But I suspect some systems, such as embedded systems, could still be 32
bit.  Do you really need more than 4 GB of RAM in the chip implanted in
your head :-)


|>We can make time() and gettimeofday() be 64 bit (the tv_sec field in
|>struct timeval for the gettimeofday() function) right now.  But look at
|>what breaks as soon as you do that ... programs already compiled to use
|>32 bits.
| 
| Yes, you would need to rev the 32 bit ABI.  Since that is a porting
| project, you can just as well skip and go to 64 bits directly.

What I think would help is having time64(), gettimeofday64().  We'll need a
replacement for struct timeval for gettimeofday64() so it has 64 bits for
the tv_sec member.  Might as well replace the tv_usec member with tv_asec
at 64 bits of attoseconds at the same time, even though such resolution of
time won't have any real use or capability for ages; just get it over with.

Note, if this involves making a new syscall, don't make two; just make one.
Let time64() be a stub that calls gettimeofday64().

As for the excess of syscalls, it might have been smarter to make just one
syscall for all 64 bit variants, through which is passed a separate code to
identify which syscall is needed.  But that's water under the bridge now.

-- 
-----------------------------------------------------------------------------
| Phil Howard KA9WGN       | http://linuxhomepage.com/      http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/   http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
0
Reply phil 4/5/2006 5:09:46 PM

On Wed, 05 Apr 2006 09:41:54 GMT Keith Thompson <kst-u@mib.org> wrote:
| phil-news-nospam@ipal.net writes:
|> On Tue, 04 Apr 2006 21:36:10 GMT Keith Thompson <kst-u@mib.org> wrote:
|> | phil-news-nospam@ipal.net writes:
|> |> On Fri, 31 Mar 2006 22:46:09 GMT Keith Thompson <kst-u@mib.org> wrote:
| [...]
|> |> | The C standard only requires time_t to be an arithmetic type capable
|> |> | of representing times.  There's no statement about the resolution; it
|> |> | needn't even be linear or monotonic.
|> |> | 
|> |> | I'm not sure what POSIX requires, but I'm failure sure it allows it to
|> |> | be more than 32 bits.
|> | 
|> | I mean "fairly sure", of course.
|>
|> It most certainly allows it.  The issue is making the transition.  If a
|> binary program is getting the time in 32 bit form, and the OS provides it
|> in 64 bit form, it won't work.  The ABI has to match.
|>
|> We can make time() and gettimeofday() be 64 bit (the tv_sec field in
|> struct timeval for the gettimeofday() function) right now.  But look at
|> what breaks as soon as you do that ... programs already compiled to use
|> 32 bits.
| 
| Not necessarily:
| 
| % uname -mo
| x86_64 GNU/Linux
| % gcc -dumpversion
| 3.4.3
| % cat time_test.c
| #include <time.h>
| #include <stdio.h>
| #include <limits.h>
| int main(void)
| {
|    time_t now = time(NULL);
|    printf("now = %ld, time_t is %d bits\n",
|           (unsigned long)now,
|           (int)(CHAR_BIT * sizeof(time_t)));
|    return 0;
| } 
| % gcc -m32 time_test.c -o time_test && ./time_test
| now = 1144229533, time_t is 32 bits
| % gcc -m64 time_test.c -o time_test && ./time_test
| now = 1144229541, time_t is 64 bits
| 
| It works by using two sets of libraries.

Of course on a 64 bit machine with a 64 bit time() and a library that
knows how to chop 64 bit syscall results down to 32 bit for the return
value, that works.  But that's not the issue I raise.  What I suggest
is that the 32 bit machines need a 64 bit time().  If you change the
actual size of time_t, that breaks it w/o recompiling everything.

Here's another alternative I suggested years ago.  Create a psuedo-64 bit
architecture based on a 32 bit CPU.  Essentially the main difference is
the size of long is increased from 32 bit to 64 bit, along with all the
other types that follow along, including time_t.  One exception would be
pointers, which could, and probably should, stay 32 bit.  This would be
a whole new architecture as far as gcc, libc, and the kernel are concerned.
The compilations would generate the same code for long as it does now for
long long to do 64 bit ints using a pair of 32 bit ints.  The ABI would
probably not be the same as a 64 bit machine since registers are still
different between them.  I'd call it "ia64on32" or some such name.  The
point is, it could run on 32 bit hardware but make everything look like a
64 bit machine at the level of user space programs in C and up.  It would
still have limitations of 4GB on user space VMs and the like.  It would
not be all that a 64 bit machine could be.  But it would be a nice way to
transition.

-- 
-----------------------------------------------------------------------------
| Phil Howard KA9WGN       | http://linuxhomepage.com/      http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/   http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
0
Reply phil 4/5/2006 5:26:34 PM

On Wed, 05 Apr 2006 10:02:05 -0000 Gordon Burditt <gordonb.omi0y@burditt.org> wrote:
|>With time_t being a signed 32 bit integer marking the number of seconds
|>since 1 Jan 1970, most of us know it will be overflowing on 19 Jan 2038
|>(6 Jan 2038 if you use the Julian calendar).  So how will this end up
|>being fixed?  I see some possibilities:
| 
| C does not require a time_t to even be a "number of <something> since
| <epoch>".  And there's no specific size for it (or any other type
| in C - minimum number of bits, yes, specific size, no).  For example,
| to convert to time_t, you could write down the date in the form 
| HHMMSSDDMMYYYYYY, treat the result as a decimal number, and convert
| to binary.  That mess isn't even monotonic.

But what C requires is not the whole picture.  This also involves POSIX.


|>1.  Redefine time_t to be a 64 bit signed integer.  This would be way
|>overkill since it is more than enough to measure the time until our star
|>is projected to die.  There's also no standard way to check for largest
|>possible value as a constant (as in INT_MAX for type int) so code can work
|>in either environment right now.
| 
| I think #1 is what's going to happen.
| 
| I would prefer (variant of #3) to redefine time_t to be a 256 bit
| signed integer as the number of yoctoseconds (10**-24 seconds) since
| the beginning of the universe.  Slight problem here:  we don't know
| when that was to any accuracy.  And it violates POSIX requirements
| for a time_t being in seconds.

Since it would be signed, you don't have to set the epoch at the beginning
of the universe.  Set it to some arbitrary time and learn to use negative
numbers in date and time calculations (hint, divison needs to use the
"truncation to negative infinity" method instead of the "truncation to zero"
method that the C standard specifies.  I have macros that do it for my own
time calculation codes.

I think 128 bits and attoseconds is adequate.  But that's just me.


|>2.  Change the units on time_t from 1 second to 2 seconds or more.  This
|>could get us to 7 Feb 2106 or beyond, but at the cost of breaking a lot of
|>code along the way.
| 
| That's going to break a heck of a lot of code.  Especially the part about
| not being able to represent times with odd seconds.

I actually use this method, at a 4 second resolution, to calculate my
DNS zone file SOA timestamps.  That limits me to no more than one update
of a zone file in any aligned 4 second period.


|>3.  Change time_t to 64 bits AND change the units to nanoseconds.  This
|>would be a versatile number.  It would get us to 11 Apr 2262 while at the
|>same time be a number that could be used for fine resolution.  But it,
|>too, would break code that assumes time_t is exactly one second steps.
| 
| Unfortunately, POSIX assumes that.

So we ultimately need something else for sub-second resolution.  And we
have gettimeof() with struct timeval.  It can be expanded to 64 bits for
both members, giving the 2nd member attosecond resolution, and a new name
of tv_asec.



|>4.  Use a completely new type and depricate time_t.  Maybe longtime_t? 
|>But this is like sweeping the problem under the rug.
| 
| I'm not sure it is if the new time representation has a sufficient
| number of bits.

I think 64 bits is plenty for second resolution, and 128 bits is plenty
for sub-second resolution, sharing the same epoch date.



|>5.  Switch from signed 32 bits to unsigned 32 bits.  That means trading
|>off the ability to calculate time before 1970 for the ability to calculate
|>time beyond 2038.  I'm sure something will break.
| 
| I believe some systems already have an unsigned time_t.

And some with signed have given a special meaning to the value of -1.


|>So what will be done?  Or what do you think should be done?
|>
|>If this will require changes in code to make code that is portably Y2038
|>compliant (methods 1 and 5 would not break any of my code) I'd like to
|>start using that method now.
| 
| I think what will happen is #1.

I don't see any movement on that for 32 bit machines, which will be around
for quite a while.  They are the ones that will be breaking gradually more
and more as future calculations involve dates beyond 2038.

One work around is to create a set of date/time calculation tools that use
a type entirely different than time_t.  This type would then be 64 bits or
more on all architectures, and the same on all of them as well.  I think
64 bits is enough with microsecond resolution, and maybe even nanosecond.
If this can get adopted and standardized soon, then it can be the way that
apps do their calculations.  Furthermore, the function it provides to get
the current time be designed to take negative values from a signed 32 bit
time_t and revert then to the unsigned value to extend the ability to get
the current time to 06:28:15 on 7 February 2106.

See, the real problem isn't so much the fact that time() returns a 32 bit
value, but rather, that we are too tied up with time_t for other stuff like
date/time calculations and using C Library tools like ctime().  I think the
simplest change would be a whole new set of date/time calculation tools for
applications to use that isn't tied to time_t, and is universally consistent
over all platforms as long as that platform has a way to work with a 64 bit
integer (the way I would prefer to do it instead of a struct).

-- 
-----------------------------------------------------------------------------
| Phil Howard KA9WGN       | http://linuxhomepage.com/      http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/   http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
0
Reply phil 4/5/2006 5:50:45 PM

phil-news-nospam@ipal.net writes:

>But that leaves 32 bit OSes ... which already have quite a number of 64
>bit interfacing as it is, just not for time() or gettimeofday() out in
>the cold.


>Will 32 bit OSes still be around in 2038?  I think the better question is
>will we need to calculate beyond 2038 while 32 bit OSes are still here.

They'll hopefully dead at that time :-)

All current architectures seems to have sprung a 64 bit version,
"IA32" being the last to do so.

Sun stopped making 32 bit CPUs in the late 90s, 7 or 8 years ago.  We
still support them with Solaris 9 (2002) but no longer with Solaris 10
(2005).  Because of our service lifetimes we need to stop shipping 32
bit application support around 2028 (or stop supporting it, anyway)

Intel is still making 32 bit CPUs but is slowly moving to a x64
only line.

>Hosted machines will mostly all be 64 bit or maybe even 128 but by 2038.
>But I suspect some systems, such as embedded systems, could still be 32
>bit.  Do you really need more than 4 GB of RAM in the chip implanted in
>your head :-)

There will be no point in making special CPUs for those applications.

>What I think would help is having time64(), gettimeofday64().  We'll need a
>replacement for struct timeval for gettimeofday64() so it has 64 bits for
>the tv_sec member.  Might as well replace the tv_usec member with tv_asec
>at 64 bits of attoseconds at the same time, even though such resolution of
>time won't have any real use or capability for ages; just get it over with.

No; that won't help at all.

Please check the completely list of system and library calls which take
or return timestamps; you'll find the list is really long.

stat, lstat, fstat, statvfs, fstatvfs, get/setrlimit (CPU time limit)
adjtime, gettimeofday, setitimer, getitimer, utimes, utime, rusage,
select, clock_set/gettime, nanosleep, pthread*timed*.

Then there's all the library routines.

My guess is that it will take a complete second ABI and that you really
should change the object file format (e.g., bump the ELF header version/type)
so that mixing the executable and object types is not possible.

Unless, of course, you like the combinatory explosion of
stat, stat64 (largefiles), stat_bigtime (64 bit time_t), stat64_bigtime
(large files and 64 bit time).  Horror of horrors.

Casper
0
Reply Casper 4/5/2006 6:18:37 PM

On 05 Apr 2006 18:18:37 GMT Casper H.S. Dik <Casper.Dik@sun.com> wrote:
| phil-news-nospam@ipal.net writes:
| 
|>But that leaves 32 bit OSes ... which already have quite a number of 64
|>bit interfacing as it is, just not for time() or gettimeofday() out in
|>the cold.
| 
| 
|>Will 32 bit OSes still be around in 2038?  I think the better question is
|>will we need to calculate beyond 2038 while 32 bit OSes are still here.
| 
| They'll hopefully dead at that time :-)
| 
| All current architectures seems to have sprung a 64 bit version,
| "IA32" being the last to do so.
| 
| Sun stopped making 32 bit CPUs in the late 90s, 7 or 8 years ago.  We
| still support them with Solaris 9 (2002) but no longer with Solaris 10
| (2005).  Because of our service lifetimes we need to stop shipping 32
| bit application support around 2028 (or stop supporting it, anyway)
| 
| Intel is still making 32 bit CPUs but is slowly moving to a x64
| only line.
| 
|>Hosted machines will mostly all be 64 bit or maybe even 128 but by 2038.
|>But I suspect some systems, such as embedded systems, could still be 32
|>bit.  Do you really need more than 4 GB of RAM in the chip implanted in
|>your head :-)
| 
| There will be no point in making special CPUs for those applications.

Some embedded systems have 8 bit even today.  Of course you don't expect
Unix to run on those.  But in 2038 when those systems could be running
32 bit, you might.


|>What I think would help is having time64(), gettimeofday64().  We'll need a
|>replacement for struct timeval for gettimeofday64() so it has 64 bits for
|>the tv_sec member.  Might as well replace the tv_usec member with tv_asec
|>at 64 bits of attoseconds at the same time, even though such resolution of
|>time won't have any real use or capability for ages; just get it over with.
| 
| No; that won't help at all.
| 
| Please check the completely list of system and library calls which take
| or return timestamps; you'll find the list is really long.
| 
| stat, lstat, fstat, statvfs, fstatvfs, get/setrlimit (CPU time limit)
| adjtime, gettimeofday, setitimer, getitimer, utimes, utime, rusage,
| select, clock_set/gettime, nanosleep, pthread*timed*.

Good point.


| Then there's all the library routines.
| 
| My guess is that it will take a complete second ABI and that you really
| should change the object file format (e.g., bump the ELF header version/type)
| so that mixing the executable and object types is not possible.
| 
| Unless, of course, you like the combinatory explosion of
| stat, stat64 (largefiles), stat_bigtime (64 bit time_t), stat64_bigtime
| (large files and 64 bit time).  Horror of horrors.

Not really.  I wish they had just dived in and made the regular stuff be
64 bit, and have interfacing library for both 32 bit and 64 bit apps ...
on both 32 bit and 64 bit architectures for those OSes that will still
be doing 32 bit for a long time (BSD and Linux).

-- 
-----------------------------------------------------------------------------
| Phil Howard KA9WGN       | http://linuxhomepage.com/      http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/   http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
0
Reply phil 4/5/2006 6:47:55 PM

phil-news-nospam@ipal.net writes:
[...]
> Of course on a 64 bit machine with a 64 bit time() and a library that
> knows how to chop 64 bit syscall results down to 32 bit for the return
> value, that works.  But that's not the issue I raise.  What I suggest
> is that the 32 bit machines need a 64 bit time().  If you change the
> actual size of time_t, that breaks it w/o recompiling everything.

If you change the size of time_t, you're going to have to recompile
everything anyway.  That's not much of a problem; everything is
commonly recompiled for new OS releases anyway.

> Here's another alternative I suggested years ago.  Create a psuedo-64 bit
> architecture based on a 32 bit CPU.  Essentially the main difference is
> the size of long is increased from 32 bit to 64 bit, along with all the
> other types that follow along, including time_t.  One exception would be
> pointers, which could, and probably should, stay 32 bit.  This would be
> a whole new architecture as far as gcc, libc, and the kernel are concerned.
> The compilations would generate the same code for long as it does now for
> long long to do 64 bit ints using a pair of 32 bit ints.  The ABI would
> probably not be the same as a 64 bit machine since registers are still
> different between them.  I'd call it "ia64on32" or some such name.  The
> point is, it could run on 32 bit hardware but make everything look like a
> 64 bit machine at the level of user space programs in C and up.  It would
> still have limitations of 4GB on user space VMs and the like.  It would
> not be all that a 64 bit machine could be.  But it would be a nice way to
> transition.

There's no need to change the size of "long" on 32-bit systems.  Just
make time_t a typedef for long long, and you're pretty much done
(unless I'm missing something).

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
San Diego Supercomputer Center             <*>  <http://users.sdsc.edu/~kst>
We must do something.  This is something.  Therefore, we must do this.
0
Reply Keith 4/5/2006 8:41:31 PM

14 Replies
227 Views

(page loaded in 0.13 seconds)


Reply: