By kal

2009-01-22 23:12:55 8 Comments

I searched my Linux box and saw this typedef:

typedef __time_t time_t;

But I could not find the __time_t definition.


@Ciro Santilli 新疆改造中心996ICU六四事件 2016-03-18 23:48:05


William Brendel quoted Wikipedia, but I prefer it from the horse's mouth.

C99 N1256 standard draft 7.23.1/3 "Components of time" says:

The types declared are size_t (described in 7.17) clock_t and time_t which are arithmetic types capable of representing times

and 6.2.5/18 "Types" says:

Integer and floating types are collectively called arithmetic types.

POSIX 7 sys_types.h says:

[CX] time_t shall be an integer type.

where [CX] is defined as:

[CX] Extension to the ISO C standard.

It is an extension because it makes a stronger guarantee: floating points are out.

gcc one-liner

No need to create a file as mentioned by Quassnoi:

echo | gcc -E -xc -include 'time.h' - | grep time_t

On Ubuntu 15.10 GCC 5.2 the top two lines are:

typedef long int __time_t;
typedef __time_t time_t;

Command breakdown with some quotes from man gcc:

  • -E: "Stop after the preprocessing stage; do not run the compiler proper."
  • -xc: Specify C language, since input comes from stdin which has no file extension.
  • -include file: "Process file as if "#include "file"" appeared as the first line of the primary source file."
  • -: input from stdin

@chux 2018-01-04 21:44:48

What is ultimately a time_t typedef to?

Robust code does not care what the type is.

C species time_t to be a real type like double, long long, int64_t, int, etc.

It even could be unsigned as the return values from many time function indicating error is not -1, but (time_t)(-1) - This implementation choice is uncommon.

The point is that the "need-to-know" the type is rare. Code should be written to avoid the need.

Yet a common "need-to-know" occurs when code wants to print the raw time_t. Casting to the widest integer type will accommodate most modern cases.

time_t now = 0;
printf("%jd", (intmax_t) now);
// or 
printf("%lld", (long long) now);

Casting to a double or long double will work too, yet could provide inexact decimal output

printf("%.16e", (double) now);

@Owl 2019-02-14 17:00:29

I'm in a need to know situation because i need to transfer time from an ARM system to an AMD64 system. time_t is 32bits on the arm, and 64bits on the server. if I translate the time into a format, and send a string, it's inefficient and slow. Therefore it's much better to just send the entire time_t and sort it out on the server end. However, I need to understand the type a bit more because I don't want the number to get mangled up by differing endianness between systems, so i need to use htonl... but first, on a need to know basis, I want to find out the underlying type ;)

@abcoep 2014-08-24 15:01:56

time_t is of type long int on 64 bit machines, else it is long long int.

You could verify this in these header files:

time.h: /usr/include
types.h and typesizes.h: /usr/include/x86_64-linux-gnu/bits

(The statements below are not one after another. They could be found in the resp. header file using Ctrl+f search.)

1)In time.h

typedef __time_t time_t;

2)In types.h

# define __STD_TYPE     typedef  
__STD_TYPE __TIME_T_TYPE __time_t;  

3)In typesizes.h

#define __TIME_T_TYPE       __SYSCALL_SLONG_TYPE  
#if defined __x86_64__ && defined __ILP32__  

4) Again in types.h

#define __SLONGWORD_TYPE    long int
#if __WORDSIZE == 32
# define __SQUAD_TYPE       __quad_t
#elif __WORDSIZE == 64
# define __SQUAD_TYPE       long int  

#if __WORDSIZE == 64
typedef long int __quad_t;  
__extension__ typedef long long int __quad_t;

@Ciro Santilli 新疆改造中心996ICU六四事件 2016-03-19 09:14:28

Those files are provided by glibc on Ubuntu 15.10 BTW.

@Zan Lynx 2016-11-14 17:13:13

It isn't long int everywhere. See…

@pwrgreg007 2012-06-13 04:26:34

The answer is definitely implementation-specific. To find out definitively for your platform/compiler, just add this output somewhere in your code:

printf ("sizeof time_t is: %d\n", sizeof(time_t));

If the answer is 4 (32 bits) and your data is meant to go beyond 2038, then you have 25 years to migrate your code.

Your data will be fine if you store your data as a string, even if it's something simple like:

FILE *stream = [stream file pointer that you've opened correctly];
fprintf (stream, "%d\n", (int)time_t);

Then just read it back the same way (fread, fscanf, etc. into an int), and you have your epoch offset time. A similar workaround exists in .Net. I pass 64-bit epoch numbers between Win and Linux systems with no problem (over a communications channel). That brings up byte-ordering issues, but that's another subject.

To answer paxdiablo's query, I'd say that it printed "19100" because the program was written this way (and I admit I did this myself in the '80's):

time_t now;
struct tm local_date_time;
now = time(NULL);
// convert, then copy internal object to our object
memcpy (&local_date_time, localtime(&now), sizeof(local_date_time));
printf ("Year is: 19%02d\n", local_date_time.tm_year);

The printf statement prints the fixed string "Year is: 19" followed by a zero-padded string with the "years since 1900" (definition of tm->tm_year). In 2000, that value is 100, obviously. "%02d" pads with two zeros but does not truncate if longer than two digits.

The correct way is (change to last line only):

printf ("Year is: %d\n", local_date_time.tm_year + 1900);

New question: What's the rationale for that thinking?

@Adrian Günter 2014-08-30 05:30:58

You should probably use the %zu format specifier to format size_t values (as yielded by sizeof), as they are unsigned (u) and of length size_t (z

@chux 2018-01-04 21:32:53

... or use printf ("sizeof time_t is: %d\n", (int) sizeof(time_t)); and avoid the z issue.

@William Brendel 2009-01-22 23:29:26

The time_t Wikipedia article article sheds some light on this. The bottom line is that the type of time_t is not guaranteed in the C specification.

The time_t datatype is a data type in the ISO C library defined for storing system time values. Such values are returned from the standard time() library function. This type is a typedef defined in the standard header. ISO C defines time_t as an arithmetic type, but does not specify any particular type, range, resolution, or encoding for it. Also unspecified are the meanings of arithmetic operations applied to time values.

Unix and POSIX-compliant systems implement the time_t type as a signed integer (typically 32 or 64 bits wide) which represents the number of seconds since the start of the Unix epoch: midnight UTC of January 1, 1970 (not counting leap seconds). Some systems correctly handle negative time values, while others do not. Systems using a 32-bit time_t type are susceptible to the Year 2038 problem.

@user25148 2009-01-23 19:21:01

Note, however, that time_t values are usually only stored in memory, not on disk. Instead, time_t is converted to text or some other portable format for persistent storage. That makes the Y2038 problem to not really be a problem.

@Heath Hunnicutt 2011-05-20 01:39:34

@Lars Wirzenius - I thought dirents contained time_ts?

@user25148 2011-05-22 08:44:53

@Heath: on a specific system, where the same people create the operating system and C library, using time_t in the on-disk data structure may happen. However, since filesystems are often read by other operating systems, it'd be silly to define the filesystem based on such implementation-dependent types. For example, the same filesystem might be used on both 32-bit and 64-bit systems, and time_t might change size. Thus, filesystems are need to be defined more exactly ("32-bit signed integer giving number of seconds since the start of 1970, in UTC") than just as time_t.

@Michał Górny 2012-08-30 21:06:51

As a note: the linked Wikipedia article has been removed, and it now redirects to list of time.h contents. That article links to but the cited content is nowhere to be found…

@Zeta 2013-03-13 07:51:39

@MichałGórny: Fixed, as long as articles aren't deleted you can always have a look at the history in order to find the correct version.

@Noitidart 2015-03-28 20:26:29

Do you think the article meant unsigned_int? or did it really mean signed?

@BlackJack 2018-04-13 13:06:05

@Noitidart It meant signed, because otherwise it would be impossible to encode time before the origin point (epoch on Unix/Linux).

@user2356685 2018-06-25 02:19:29

They don't count leap years in Unix timestamps. That is stupid. Linux is very poorly programmed. We need to replace this antiquated code with code that does not suck.

@Ry- 2018-07-08 17:13:39

@Cale: Leap seconds, not leap years…

@Mark Amery 2019-04-06 19:30:15

-1; the claim quoted from Wikipedia that POSIX guarantees that time_t is signed is incorrect.… dictates that various things must be a "signed integer type" or "unsigned integer type", but of time_t it says merely that it "shall be an integer type". An implementation can make time_t unsigned and still be POSIX-compliant.

@poolie 2012-02-21 01:59:38

Typically you will find these underlying implementation-specific typedefs for gcc in the bits or asm header directory. For me, it's /usr/include/x86_64-linux-gnu/bits/types.h.

You can just grep, or use a preprocessor invocation like that suggested by Quassnoi to see which specific header.

@bvrwoo_3376 2011-10-28 17:52:17

time_t is just typedef for 8 bytes (long long/__int64) which all compilers and OS's understand. Back in the days, it used to be just for long int (4 bytes) but not now. If you look at the time_t in crtdefs.h you will find both implementations but the OS will use long long.

@Vincent 2014-02-17 13:51:28

all compilers and OSes? No. On my linux system the compiler takes the 4 bytes signed implementation.

@Owl 2019-02-14 17:02:31

On Zynq 7010 systems time_t is 4bytes.

@user 2009-01-22 23:26:37

It's a 32-bit signed integer type on most legacy platforms. However, that causes your code to suffer from the year 2038 bug. So modern C libraries should be defining it to be a signed 64-bit int instead, which is safe for a few billion years.

@Quassnoi 2009-01-22 23:23:29

[root]# cat time.c

#include <time.h>

int main(int argc, char** argv)
        time_t test;
        return 0;

[root]# gcc -E time.c | grep __time_t

typedef long int __time_t;

It's defined in $INCDIR/bits/types.h through:

# 131 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/typesizes.h" 1 3 4
# 132 "/usr/include/bits/types.h" 2 3 4

@ssice 2012-05-10 17:21:38

I see both typedef __int32_t __time_t; and typedef __time_t time_t; in a FreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 [email protected]:/usr/obj/usr/src/sys/MYXEN i386. Your results are explicitly set like that in Linux (at least on 2.6.32-5-xen-amd64 from Debian).

@Viet 2012-12-13 10:14:02

Neat trick! So all types can be discovered this way

@Ciro Santilli 新疆改造中心996ICU六四事件 2016-03-18 23:48:54

@Viet also possible with an one-liner without creating a file:

@Eclipse 2009-01-22 23:21:31

Under Visual Studio 2008, it defaults to an __int64 unless you define _USE_32BIT_TIME_T. You're better off just pretending that you don't know what it's defined as, since it can (and will) change from platform to platform.

@Rob Kennedy 2009-01-23 00:35:50

That usually works, but if your program is meant to keep track of things that will happen 30 years from now, it's pretty important that you not have a signed 32-bit time_t.

@paxdiablo 2009-01-23 00:40:03

@Rob, bah, leave it! We'll just start running around like headless chickens in 2036, the same as we did for Y2K. Some of us will make a bucketload of money from being Y2k38 consultants, Leonard Nimoy will bring out another hilarious book about how we should all go and hide in the forest...

@paxdiablo 2009-01-23 00:40:53

... and it'll all blow over, the public wondering what all the fuss was about. I may even come out of retirement to make some money for the kids' inheritance :-).

@paxdiablo 2009-01-23 00:42:00

BTW, we only found one Y2K bug and that was a web page which listed the date as Jan 1, 19100. Exercise for the reader as to why...

@Eclipse 2009-01-23 03:31:16

@Pax - very nice!

@Rob Kennedy 2009-01-23 05:05:52

If the event to happen in 30 years is "expire this backup," then you might be in trouble NOW, not in 2038. Add 30 years to today's 32-bit time_t, and you get a date in the past. Your program looks for events to process, finds one that's overdue (by 100 years!), and executes it. Oops, no more backup.

@bonsaiviking 2017-10-10 16:10:23

Y2K was a non-event because of the efforts of programmers and engineers working specifically to avoid it. If there had been a "nothing will go wrong" attitude about it then, it would have had disastrous results. But also remember there were far fewer "computers" then: "smart" appliances and the Internet of Things weren't happening.

Related Questions

Sponsored Content

13 Answered Questions

[SOLVED] What is the effect of extern "C" in C++?

61 Answered Questions

[SOLVED] What is the difference between String and string in C#?

31 Answered Questions

41 Answered Questions

[SOLVED] How do I find all files containing specific text on Linux?

6 Answered Questions

[SOLVED] What are the differences between type() and isinstance()?

4 Answered Questions

[SOLVED] What does the C ??!??! operator do?

  • 2011-10-19 16:56:59
  • Peter Olson
  • 242121 View
  • 1822 Score
  • 4 Answer
  • Tags:   c operators trigraphs

5 Answered Questions

[SOLVED] What is ":-!!" in C code?

16 Answered Questions

[SOLVED] Merge / convert multiple PDF files into one PDF

12 Answered Questions

[SOLVED] typedef struct vs struct definitions

  • 2009-11-04 17:21:57
  • user69514
  • 608770 View
  • 714 Score
  • 12 Answer
  • Tags:   c struct typedef

Sponsored Content