1

According to my understanding time_t rawtime = 0xffFFffFF is GMT: Sunday, February 7, 2106 6:28:15 AM

But the program below brings Thu 1970-01-01 02:59:59 MSK in some compilers and just crashes in others.

int main() 
{

    time_t rawtime = 0xffFFffFF;
    struct tm  ts;
    char       buf[80];

    ts = *localtime(&rawtime);
    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
    printf("%s\n", buf);
    return 0;
}

Error behaviors appears when rawtime >0x7fFFffFF. Why? How to solve this?

UPD: I need to have array of alarms and proceed action when time comes. This is embedded system and I can't waste memory and resources for complicated data types.

phuclv
  • 37,963
  • 15
  • 156
  • 475
vico
  • 17,051
  • 45
  • 159
  • 315
  • 1
    Use a different compiler that has a larger time_t ? – M.M Feb 14 '21 at 20:30
  • 1
    `time_t` is signed, therefore all values above 0x7fffffff are negative – qrdl Feb 14 '21 at 20:30
  • @qrdl It may or may not be signed – M.M Feb 14 '21 at 20:31
  • 4
    *localtime crashes* is probably inaccurate. The fact that you don't check the return value of `localtime` before dereferencing it is more likely the cause of the crash. – kaylum Feb 14 '21 at 20:33
  • @M.M `time_t` is typically signed, on most platforms, and because of this we have year 2038 problem – qrdl Feb 14 '21 at 20:34
  • @qrdl everyone will be 64-bit by 2038 - hopefully! – M.M Feb 14 '21 at 20:45
  • When you say "How to solve this?", what problem are you trying to solve? – Steve Summit Feb 14 '21 at 20:51
  • @Steve Summit I need to have array of alarms and proceed action when time comes. This is embedded system and I can't waist memory and resources for complicated data types. – vico Feb 15 '21 at 12:37
  • @vico Do you need to be able to set alarms that will go off after 2037, or before 1970? If you need to handle dates beyond 2037, I'm afraid you may need a different data type, and/or a constraint on the compiler and C library you use. – Steve Summit Feb 15 '21 at 13:13

2 Answers2

2

On most platforms type time_t is a signed integer. Also on most platforms time_t counts time from January 1, 1970. Combining those two facts, we have negative time_t values corresponding to dates before January 1, 1970.

If time_t on your machine is a signed 32-bit integer, 0xffffffff is -1. Theoretically, therefore, this value corresponds to 23:59:59 UTC on December 31, 1969 — that is, one second before UTC midnight. But in some contexts, -1 indicates an error. So although I've never encountered it, I'm not completely surprised if there's a localtime() implementation out there that treats a value of -1 on input as an error.

You said it "crashed", but that's partly your fault. localtime indicates failure by returning a null pointer. So it's safer to write

struct tm *ts;

ts = localtime(&rawtime);
if(ts == NULL) {
    fprintf(stderr, "localtime failed\n");
    exit(1);
}

strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);

If time_t is a signed, 32-bit value, its maximum value is 2147483647 which (still assuming the Unix epoch of 1970) corresponds to January 19, 2038 at 03:14:07 UTC. The minimum value, 2147483648, corresponds to December 13, 1901 at 20:45:52 UTC.

You're right, if time_t were treated as unsigned, the maximum 32-bit value would be 4294967295 and would correspond to the date and time in 2106 you mentioned.

If time_t is a 64-bit type, as is increasingly popular (and more or less necessary in order to forestall the y2.038k problem), the maximum value is so big that it's practically meaningless. (It's so big that the year can't even be represented in 32 bits.)

Finally, it's worth remembering that the interpretation of time_t is platform-specific. Theoretically, it doesn't necessarily count seconds, it doesn't necessarily count from January 1, 1970, and it's not even necessarily an integer. Even where those facts do hold, there's no rule that says time_t necessarily has to be signed, so in a program designed for widespread portability I wouldn't count on there being values corresponding to 1901–1970, since on some platforms they might correspond to 2038–2106, after all.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
1

The type and range of time_t are implementation-defined and there are no minimum requirements. It could be signed, unsigned, 32-bit, 64-bit, floating point, etc.

If the compiler you're using doesn't have a time_t whose range meets your requirements, you could:

  • use a different compiler, or
  • avoid using time_t, or
  • restructure your program to work within the limits of time_t on your compiler.

As mentioned in comments, the "crash" is likely due to localtime returning a null pointer due to the out of range input, and you dereference it without first checking for null.

M.M
  • 138,810
  • 21
  • 208
  • 365