16

I have some code which is built both on Windows and Linux. Linux at this point is always 32-bit but Windows is 32 and 64-bit. Windows wants to have time_t be 64-bit and Linux still has it as 32-bit. I'm fine with that, except in some places time_t values are converted to strings. So when time_t is 32-bit it should be done with %d and when it is 64-bit with %lld...

What is the smart way to do this? Also: any ideas how I may find all places where time_t's are passed to printf-style functions to address this issue?


Edit: I came up with declaring TT_FMT as %d or %lld and then changing my printfs as in

printf("time: %d, register: blah")

to be

printf("time: " TT_FMT ", register: blah")

Is there a better way? And how do I find them all?

phuclv
  • 37,963
  • 15
  • 156
  • 475
MK.
  • 33,605
  • 18
  • 74
  • 111
  • Actually, I think you want to use unsigned format specifiers. – Tim Post Mar 18 '10 at 03:42
  • 2
    Tim, it is signed on both Linux and Windows (see http://stackoverflow.com/questions/471248/what-is-ultimately-a-time-t-typedef-to). Otherwise, it wouldn't be able to represent Dennis Ritchie's entire life. ;) (http://en.wikipedia.org/wiki/Unix_time#Representing_the_number) – Matthew Flaschen Mar 18 '10 at 04:24
  • 2
    Actually, time_t is also 64 bits wide on contemporary glibcs for Linux x86_64. – user562374 Feb 07 '11 at 01:42
  • @user562374 only on 64-bit Linux. 32-big glibc has just got 64-bit time_t support in [version 2.32](https://stackoverflow.com/a/60709400/995714) – phuclv Dec 17 '20 at 00:50
  • It is not Windows that determines the size of `time_t`, but rather the C library you are using. For example in MSVC you can define `_USE_32BIT_TIME_T` to force 32 bit time. However I am pretty sure that the assertion _"Linux at this point is always 32-bit"_ is untrue. It is messier than that! – Clifford Jul 07 '23 at 16:37

4 Answers4

11

According to the C standard, time_t is an arithmetic type, "capable of representing times". So, it could be double for example. (Posix mentions this more explicitly, and also guarantees that time() returns the number of seconds since the Epoch—the latter is not guaranteed by the C standard.)

Maybe the cleanest solution is to convert the value to whatever type you want. You may want one of unsigned long long or unsigned long:

printf("%llu\n", (unsigned long long)t);
Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
  • This has always seemed like the cleanest method to me. It seems a pity that `printf` didn't include a format specifier for `time_t` values, even if it was just the `%c` behaviour from `strftime`. – caf Mar 18 '10 at 04:28
  • 1
    Thanks, I think I like it, except time_t is signed; I'll probably use int64_t. – MK. Mar 18 '10 at 13:17
  • 1
    How about `%jd` and `intmax_t`? – S.S. Anne Jan 08 '20 at 15:18
  • 1
    @JL2210 Yeah, that should work.. although I _think_ `"%" PRIdMAX` might be more portable. – Alok Singhal Jan 08 '20 at 19:16
7

I think the only truly portable way is to use strftime to convert the time_t to a string.

If you're sure that you're only operating on platforms where time_t is an int, you could cast to intmax_t (from stdint.h) and print it using PRIdMAX (from inttypes.h).

porges
  • 30,133
  • 4
  • 83
  • 114
  • 2
    Now, (9 years after this answer), you could use `%jd` in place of `PRIdMAX` as in `snprintf(str, sizeof(str), "%jd", (intmax_t)i_am_a_time_t_var)` – John Hascall Apr 18 '19 at 18:10
3

If you want to go with the macro specifier, I would recommend one minor tweak. Instead of encapsulating the entire specifier, encapsulate just the modifier:

#ifdef 64_BIT_TIME
  #define TT_MOD "ll"
#else
  #define TT_MOD ""
#endif

and then using it like this:

printf("current time in seconds is: %" TT_MOD "u", time(0));

The reason why is that while you primarily want the second in decimal, every so often you may want hex (or perhaps you want leading 0's). By only having the modifier there, you can easily write:

"%" TT_MOD "x"   // in hex
"%08" TT_MOD "d"  // left pad with 0's so the number is at least 8 digits
R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
  • 4
    Minor nitpick; macro names can't start with digits. I would probably go for a name more like the `` names, without encroaching on the reserved namespace (ISO/IEC 9899:2011 §7.31.6 _Macros that begin with either PRI or SCN, and either a lowercase letter or X may be added to the macros defined in the `` header_). – Jonathan Leffler Jan 16 '13 at 15:53
-1

Slight adjustment on Alok's answer, it's signed on both Windows and Linux, so:

printf("%lld\n", t);

is cleaner.

ericcurtin
  • 1,499
  • 17
  • 20