Maximum values for time_t (struct timespec)

39,658

Solution 1

A time_t is simply a long int.
It's defined in (on my Ubuntu linux system) /usr/include/time.h, however the definition stretches back all the way to /usr/include/bits/types.h, where __SLONGWORD_TYPE (which is what __TIME_T_TYPE is defined to) is defined.

The problem with simply checking if a value is greater than, say, LONG_MAX, is that once a value exceeds this value it will automatically wrap around and become negative. Thus you can't check to see if anything is greater than this value - the macro is defined as the largest value this type can take.

You don't really want a user to input these values - unless by 'user' you mean 'developer'. The only real "safe" way to test this would be to let the user input a string (c-style, of course) and then run two checks:
1) Check to see if the user entered more digits than is allowed (a cheap trick is int(log10(number)) + 1 to count the amount of digits in a number).
2) If this is equal to the amount of digits, start comparing digit-by-digit. You can compare digit-by-digit by using a little bit of modulo arithmetic.

This is really the safest way to check whether or not the user inputs a number that's far too large. You won't run into any overflow issues this way, though it is terrifically tedious. Hope this helps.

Solution 2

Since people here are answering how to set the maximum time_t value, and make further guesswork as to its type, I thought I'd add the c++ way to do it:

#include <limits>
...
time_t maxTime = std::numeric_limits<time_t>::max();

Solution 3

I would not care so much about what goes into a time_t, but about what is reasonable. On any system that I have seen, a time_tcan encode timespans anywhere from 63 years to 1011 years (pretty much every system I know uses 64 bit numbers ever since these geniusses came up with the Y2K world-will-end thing in 1999, it remains to be seen who will notice the much bigger "event" when the year 2038 goes past).

If you reasonably expect that your program will be running for no more than 50 years, reject any value greater than 50*365*86400, or simply saturate the value. I don't expect any of the programs that I write now to be in use in 50 years (though I will not live to verify that).
On the other hand, if your system does use a 32 bit time_t, then it does not matter anyway, because the system time will have overflown in 50 years either way, so one can't construct a meaningful time anyway without shifting epoch.

If you ask "how long do you want to pause?" and the user says "250 years", I would deem it not truly incorrect program behaviour if you said "yeah right, 50 will do, too". Because, hey, the difference really isn't observable.

Solution 4

Unfortunately the ISO C standard (currently C11) does not provide any way to get the maximum value of time_t. So, unless one uses tools like Autoconf providing information, one needs to make some assumptions.

Assuming that time_t is an integer type without padding bits (which is the case on most platforms nowadays, if not all), one can probably take:

(((time_t) 1 << (sizeof(time_t) * CHAR_BIT - 2)) - 1) * 2 + 1

which is the maximum representable value for a signed integer type (but the fact that a value is representable in time_t does not mean that it is supported by the system as a time_t value).

One may also want to detect whether time_t is an integer type. The ISO C standard specifies that time_t is a real type (Clause 7.27.1). By definition, a real type is either an integer type or a real floating type (float, double or long double, and possibly others added in future versions of the standard, as mentioned in Clause 6.11.1). Thus, if time_t is not an integer type, it is necessarily a real floating type. As a consequence, one can detect whether time_t is an integer type with the test (time_t) 1 / 2 == 0.

Note: The C standard does not strictly require that (T) 1 / 2 be different from 0 if T is a floating type, but if this is not the case, I suspect that such platforms would have serious issues with floating-point calculations.

Solution 5

Taken from ISO/IEC 9899:TC3 §7.23

  1. The types declared are size_t (described in 7.17); clock_t and time_t which are arithmetic types capable of representing times; and struct tm which holds the components of a calendar time, called the broken-down time .

  2. The range and precision of times representable in clock_t and time_t are implementation-defined

Therefore you cannot make any assumption on its max value based on the C standard.

If you need to write portable code, you'll probably use the autotols. Autoconf offers the AC_CHECK_SIZEOF macro that can help you dealing with the architecture-specific data limits.

Share:
39,658

Related videos on Youtube

RajSanpui
Author by

RajSanpui

Around 9+ years experience into development C, C++, and Linux domain. Also understand Core-Java and consider it as a secondary skill. Currently, in addition to the developer responsibilities, i am also serving the role of DevOps engineer.

Updated on January 18, 2021

Comments

  • RajSanpui
    RajSanpui over 3 years

    I am using the struct timespec structure and here it is:

    struct timespec {
               time_t tv_sec;                /* Seconds */
               long   tv_nsec;               /* Nanoseconds */
    };
    

    Thing is, user will be entering the values for each of these individual members, and i want to put a check a max. value the user can enter.

    Can I take the max. value of time_t as int max value? i.e INT_MAX for tv_sec and LONG_MAX (defined in limits.h) for the tv_nsec? What will be the minimum acceptable values for both? Is it zero? I guess negative values can't be accepted? Just to add, these values will be using in a timer.

    P.S: Where is the typedef for time_t? Could not find it in time.h.

    • jfs
      jfs over 8 years
      @larsmans: your link says: "time_t shall be an integer type."
  • Ben Stott
    Ben Stott about 13 years
    Sure - this fixes the first issue (<0 as a valid value) however a user could still feasibly enter 2*LONG_MAX + 12 (though this is unlikely). This will wrap around to somewhere near 12 even though the value that was entered was ridiculously high.
  • RajSanpui
    RajSanpui about 13 years
    @Ben: ok, in that case counting the no of digits (what you suggested) seems a good one, and other which comes to my mind (but works only for timers) is, if the user enters a large value to wrap around to a +ve one, (-ve are discarded) then we check timer_startTime > timerEndTime. If not, we throw an error. What do you say?
  • Ben Stott
    Ben Stott about 13 years
    start_time = 2*LONG_MAX + 12, end_time = 2*LONG_MAX + 13 still breaks that one (admittedly, that's a ridiculously trite set of input, but it's technically possible....) Really, the only foolproof option is checking digits. Worst comes to worst you'll have to run 11 checks (and 11 mod operations), which shouldn't cost too many cpu cycles anyway....
  • RajSanpui
    RajSanpui about 13 years
    That's a nice test case to break my code :-). So counting the digits remains the only one. Thanks Ben, it was really useful.
  • M.M
    M.M about 8 years
    "A time_t is simply a long int." - maybe on your system - this is not guaranteed by any standard
  • o11c
    o11c about 8 years
    This is wrong, time_t is long long on gnux32 systems.
  • myk
    myk almost 7 years
    This gives maxTime = -9223372036854775808, which does work for a largest possible date.
  • skyking
    skyking almost 7 years
    The standard does not guarantee time_t to be a long int, it doesn't even guarantee it to be of integral type.
  • skyking
    skyking almost 7 years
    @myk On what platform/compiler/system do you get that result? I don't think that result is in line with the standard...
  • skyking
    skyking almost 7 years
    @BenStott Also <0 need not be a valid time_t. The standard allows for time_t being unsigned for example...
  • vinc17
    vinc17 almost 7 years
    The issue also arises with programs that do computations on dates, which can be in the future. Such programs should be able to work with dates in the distant future on platforms that support them. But on platforms with a limited time_t, the program should behave in a reasonable way if the dates are too large. There was an issue with Mutt with dates in the future, until my solution was implemented.
  • myk
    myk almost 7 years
    @skyking Wow, I can't recreate the result from my previous post. When I try now on fedora 26 (64 bit) + gcc, I get maxTime = 9223372036854775807, which looks like a valid answer. I was using fedora 25 (64-bit) + gcc at the time of my previous post.
  • osvein
    osvein about 4 years
    @skyking POSIX guarantees that time_t is an integer as an extension to C99
  • skyking
    skyking about 4 years
    @osvein As far as I can see C99 also only put the requirement that time_t is an arithmetic type.

Related