Unix Timestamp in C

time_t is where the Year 2038 problem actually lives. On modern 64-bit systems it is 64 bits wide; on 32-bit embedded targets it often is not.

Need to convert one value rather than write code? Use the interactive converter — it handles every unit and time zone without leaving your browser.

Current Unix timestamp

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

time_t now = time(NULL);
printf("%lld\n", (long long) now);      // 1710050400

struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);      // seconds + nanoseconds
printf("%lld.%09ld\n", (long long) ts.tv_sec, ts.tv_nsec);

Timestamp to date

time_t ts = 1710050400;
struct tm tm;
char buf[64];

gmtime_r(&ts, &tm);                      // UTC, thread-safe
strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S UTC", &tm);
puts(buf);

localtime_r(&ts, &tm);                   // uses the TZ environment variable
strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S %Z", &tm);
puts(buf);

Date to timestamp

struct tm tm = {0};
tm.tm_year = 2024 - 1900;      /* years since 1900 */
tm.tm_mon  = 3 - 1;            /* 0 = January      */
tm.tm_mday = 10;
tm.tm_hour = 6;
tm.tm_isdst = -1;              /* let the library decide */

time_t local_ts = mktime(&tm);          /* interprets tm as LOCAL time */
time_t utc_ts   = timegm(&tm);          /* interprets tm as UTC (GNU/BSD) */

Checking your time_t width

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

printf("time_t is %zu bytes\n", sizeof(time_t));
/* 8 = safe past 2038.  4 = overflows on 19 Jan 2038 03:14:07 UTC. */

Pitfalls specific to C

  • tm_year is years since 1900 and tm_mon is zero-indexed. Both are counted from the wrong base on purpose, for 1970s reasons.
  • mktime() reads tm as local time; timegm() reads it as UTC but is not in the C standard.
  • A 32-bit time_t overflows in 2038. See the guide.

Rules that apply in every language

  1. Store UTC, display local. Keep the instant in UTC everywhere in your system and convert only at the point a human reads it.
  2. Name the unit in the identifier. expires_at_ms rather than expires_at costs nothing and prevents the single most common timestamp bug.
  3. Never trust a client clock. Stamp anything security-relevant on the server. See the note on clock skew.
  4. Use 64-bit time. Anything still storing seconds in a signed 32-bit field breaks in January 2038 — see the Year 2038 problem.

The same task in other languages

Frequently asked questions

How do I get the current Unix timestamp in C?

Use the snippet in the "Current Unix timestamp" section above. C works in time_t seconds natively, so converting to another unit is a multiplication or an integer division away.

How do I convert a Unix timestamp to a date in C?

The "Timestamp to date" snippet above shows the idiomatic approach, including how to render the result in a specific time zone rather than whatever zone the machine happens to be set to.

Does C handle time zones and daylight saving correctly?

Yes, provided you pass an explicit zone rather than relying on the system default. The gotchas listed on this page cover the specific ways C makes that easy to get wrong.