localtime() crashes when pass value >0x7FFFFFFF

1

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

But programm 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 waist memory and resources for complicated data types.

c
time-t
asked on Stack Overflow Feb 14, 2021 by vico • edited Feb 15, 2021 by vico

2 Answers

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.

answered on Stack Overflow Feb 14, 2021 by Steve Summit • edited Feb 14, 2021 by Steve Summit
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.

answered on Stack Overflow Feb 14, 2021 by M.M • edited Feb 14, 2021 by M.M

User contributions licensed under CC BY-SA 3.0