2

I am experimenting with time_t variables, and this is the code in question:

#include <stdio.h>
#include <time.h>
#include <stdint.h>

struct tm epochtime;
time_t epochdate;

int main()
{
  epochtime.tm_mday = 19;
  epochtime.tm_mon = 10;
  epochtime.tm_year = 2002;
  epochtime.tm_hour = 0;
  epochtime.tm_min = 0;
  epochtime.tm_sec = 0 ;
  
  epochdate = mktime(&epochtime);

  printf("%ju\n",epochdate);
  printf("%ju\n", (uint32_t)epochdate);
  printf("%ju\n", (uint64_t)epochdate);
  printf("%ju\n", (uintmax_t)epochdate);
  printf("%Lf\n", epochdate);
  printf("%Le\n", epochdate);
}

I am trying to print the epochtime of a given date. The code compiles and has no errors, but when I compare what I get printed to what I calculate on this website, the values are not the same. For this given values in the example above the code output is:

210453397503
210453397503
18446744073709551615
18446744073709551615
-1.#QNAN0e+000
-1.#QNAN0e

while the link says that value should be 1034985600. I have tried multiple printf format specifiers because I found multiple answers here on how to print time_t variables, but none of them seems to work for me. Any ideas why?

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
BeNicePlz
  • 43
  • 6
  • `18446744073709551615` is `(uint64_t)-1` ... apparently your `mktime()` is returning `-1`: [C11 7.27.2.3](http://port70.net/~nsz/c/c11/n1570.html#7.27.2.3) -- "If the calendar time cannot be represented, the function returns the value (time_t)(-1)." – pmg Nov 01 '20 at 10:18
  • 3
    Maybe you need to shift the year (1900 years back) and month (1 month back), ... and pay attention to DST? – pmg Nov 01 '20 at 10:21
  • 1
    First step should always be the man page: *" **`tm_year`** Year (current year minus 1900)."* – Weather Vane Nov 01 '20 at 10:26
  • @pmg for the month, I was keeping the -1 shift in mind when calculating. I looked at the exact definition of struct tm and the link I have didnt specify that year is calculated since 1900. your suggestion worked btw, Thank you ! – BeNicePlz Nov 01 '20 at 10:32
  • @WeatherVane the link I looked at didn#t specify it that's why I missed that info. but the shift in years corrected the results. thank you! – BeNicePlz Nov 01 '20 at 10:34
  • In that case do you need to find a better reference? [This page](https://linux.die.net/man/3/localtime) describes `struct tm` and mentions the ranges a bit further down. I generally use the [Microsoft docs](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/crt-alphabetical-function-reference?view=msvc-160&viewFallbackFrom=vs-2019) because I use MSVC. – Weather Vane Nov 01 '20 at 10:37
  • @pmg However I am trying this on 2 compilers an online compiler and codeblocks. codeblocks still gives me wrong values even after modifying the values. do you have an idea why? – BeNicePlz Nov 01 '20 at 10:40
  • @WeatherVane I am new to coding, I am trying different small codes on different compilers. the code above after correction worked on an online compiler but not on codeblocks, it still prints wrong values. any idea why? – BeNicePlz Nov 01 '20 at 10:43
  • `printf("%Le\n", epochdate);` enable all compiler warnings and listen to them. – KamilCuk Nov 01 '20 at 10:45
  • `printf("%Lf\n", epochdate);` is unlikely to "work" on any compiler. – Weather Vane Nov 01 '20 at 10:46
  • 1
    In `printf("%ju\n", (uint32_t)epochdate);` the `j` tells `printf` that you are passing type `uintmax_t` but you are not – it's `uint32_t` so that too is *undefined behaviour*. Please see [Format specification syntax: printf](https://learn.microsoft.com/en-us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-functions). – Weather Vane Nov 01 '20 at 10:51
  • The `printf()` and `scanf()` function family are very involved: it is not a trivial exercise to explore them. It's made harder by the fact that they seem similar, but have some significant differences. – Weather Vane Nov 01 '20 at 10:58
  • @WeatherVane I am confused... what is the correct format specifier to print epochdate then?? – BeNicePlz Nov 01 '20 at 10:59
  • `printf("%ju\n", (uintmax_t)epochdate);` should be good. But you must check the `-1` result first. – Weather Vane Nov 01 '20 at 11:00
  • @WeatherVane yes it worked finally, thank you! – BeNicePlz Nov 01 '20 at 11:09

2 Answers2

2

I suppose that you want to represent the date: October 19th, 2002 00:00:00, which corresponds to the epoch timestamp that you expect: 1034985600.

In such case, you are doing it wrong. Read the manual:

Broken-down time is stored in the structure tm, which is defined in <time.h> as follows:

struct tm {
    int tm_sec;    /* Seconds (0-60) */
    int tm_min;    /* Minutes (0-59) */
    int tm_hour;   /* Hours (0-23) */
    int tm_mday;   /* Day of the month (1-31) */
    int tm_mon;    /* Month (0-11) */
    int tm_year;   /* Year - 1900 */
    int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
    int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
    int tm_isdst;  /* Daylight saving time */
};

Your year should be 2002 - 1900 = 102, and your month should be 9, not 10 (months start from 0 = January).

The correct code is:

#include <stdio.h>
#include <time.h>
#include <inttypes.h>

int main(void) {
    struct tm epochtime = {
        .tm_mday = 19,
        .tm_mon = 9,
        .tm_year = 102,
        .tm_hour = 0,
        .tm_min = 0,
        .tm_sec = 0,
        .tm_isdst = -1
    };

    time_t epochdate = mktime(&epochtime);
    if (epochdate == (time_t)(-1)) {
        perror("mktime failed");
        return 1;
    }

    printf("%" PRIuMAX "\n", (uintmax_t)epochdate);
    return 0;
}

Which correctly outputs 1034985600 as you expect.

The problem with your code is most likely that mktime is not able to correctly represent the "wrong" date you provide and returns -1, which you then print as unsigned and becomes a huge nonsensical number.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
0

printf epochtime shows wrong values

There is no specified matching print specifier for time_t. All the printf() except printf("%ju\n", (uintmax_t)epochdate); can lead to undefined behavior (UB).

... multiple answers here on how to print time-t variables, but none of them seems to work for me. Any ideas why?

time_t is a type capable of representing times.

The range and precision of times representable in clock_t and time_t are implementation-defined. C17dr § 7.27.1 4


Print using a cast. As time_t is very commonly a signed integer type, cast to a wide signed type:

time_t t;
time(&t);
printf("%jd", (intmax_t) t);
// or pre-C99
printf("%ld", (long) t);

or for wide portability at the small risk of losing some precision,

printf("%f", (double) t);

printf("%ju\n", (uintmax_t)epochdate); --> 18446744073709551615 is certainly the result of mktime(&epochtime); returning -1 due to a conversion error, likely due to range error with epochtime.tm_year = 2002;. .tm_year is the year since 1900. @pmg

Best to zero out epochtime first to initialize all members - there may be more than 9.

struct tm epochtime = {0};
epochtime.tm_mday = 19;
epochtime.tm_mon = 10 - 1;       // Months since January
epochtime.tm_year = 2002 - 1900; // Year since 1900
epochtime.tm_isdst = -1;         // Let system daylight daylight time for that date
epochdate = mktime(&epochtime);  // epochtime is assumed here to be a local time
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • `tm_isdst` is set by `mktime` regardless. – Marco Bonelli Nov 01 '20 at 13:29
  • 1
    @MarcoBonelli All of the members of `struct tm` may be set by `mktime()` to bring them into primary range. To initialize `.tm_isdst` to zero (as in your answer) forces `mktime()` to assess `epochtime` as _standard time_ - even in the summer. Setting it to -1, allows `mktime()` to assess `epochtime` as a daylight time with summer timestamps, after which, that member is set to 0,1. – chux - Reinstate Monica Nov 01 '20 at 13:43