C++ Unix Timestamp: time(), chrono & the timegm/mktime gotcha
C++ has two eras: the C <time.h> functions (fast, but full of timezone and thread-safety traps) and std::chrono (type-safe since C++11, with clock conversion since C++20). This guide covers both, including the timegm-vs-mktime trap that shifts values by the local offset.
Get the current Unix timestamp
#include <ctime>
#include <chrono>
// C-style: whole seconds
std::time_t sec = std::time(nullptr); // 1767225600
// C++11+ chrono: seconds and milliseconds as typed durations
using namespace std::chrono;
auto now = system_clock::now();
auto s = duration_cast<seconds>(now.time_since_epoch()).count(); // 1767225600
auto ms = duration_cast<milliseconds>(now.time_since_epoch()).count(); // 1767225600123
Convert a timestamp to a date
gmtime() gives a std::tm in UTC; localtime() in the
process's configured timezone (set via tzset/TZ, not per-call). Both
return pointers to shared static buffers — copy the std::tm immediately or use
the _r variants. std::put_time formats it.
#include <ctime>
#include <iomanip>
#include <sstream>
std::time_t ts = 1767225600;
std::tm utc = *std::gmtime(&ts); // UTC — copy before any other call
std::ostringstream out;
out << std::put_time(&utc, "%Y-%m-%d %H:%M:%S");
std::string s = out.str(); // "2026-01-01 00:00:00"
// C++20: chrono can format directly
// std::cout << std::chrono::floor<std::chrono::seconds>(std::chrono::system_clock::from_time_t(ts));
Convert a date back to a timestamp
This is the trap. mktime() interprets the std::tm as
local time; timegm() interprets it as UTC. The
two differ by your timezone offset. timegm is not in the C standard (it is a
POSIX/glibc extension) — on Windows, use
_mkgmtime().
#include <ctime>
std::tm t{};
t.tm_year = 2026 - 1900;
t.tm_mon = 0; // January
t.tm_mday = 1;
std::time_t as_utc = timegm(&t); // 1767225600 — UTC (POSIX; _mkgmtime on Windows)
std::time_t as_local = mktime(&t); // local-time interpretation — off by the offset
Naive vs aware: everything is naive unless you say so
- std::time_t — an integer; no zone anywhere. Meaning is only as good as the convention that produced it (usually UTC).
- std::tm — naive wall-clock fields; the conversion function (
mktimevstimegm) decides the zone. - std::chrono time_point — also zone-less, but C++20's
zoned_timeadds explicit zones and DST-aware arithmetic. - Rule: store
time_t(UTC by convention), convert tostd::tmonly for display, and usetimegm/_mkgmtimeon the way back.
Native precision: nanoseconds (chrono)
std::chrono::system_clock exposes whatever the OS clock provides — nanoseconds on
Linux, ~100ns on Windows. C-style time() is whole seconds; get sub-second parts
from clock_gettime(CLOCK_REALTIME, ...) or chrono, and combine with
duration_cast rather than floating-point math.
Common pitfalls
- mktime vs timegm — local vs UTC interpretation; the classic off-by-offset bug.
- gmtime/localtime buffers — shared static state; the next call overwrites your struct (thread-unsafe too — use
gmtime_r). - time_t is 32-bit on old platforms — 2038 wraps; compile 64-bit (
time_tis 64-bit on all modern 64-bit targets). - chrono epoch —
system_clockis Unix-epoch-based, butsteady_clockis not — never mix them for timestamps.
Try it live
Verify values in the epoch converter, or copy the current timestamp from the C++ snippet tab on the homepage.
First published · Last reviewed · Maintained and developed by the Real Epoch Converter team · [email protected] · Contact · Methodology
Unix time in every language
JavaScript · Python · PHP · SQL · Go · Java · C# · Rust · C++ · PowerShell
Prefer the point-and-click version? The epoch time converter on the home page handles seconds, milliseconds, and microseconds in any timezone — every snippet on this page produces the same value that tool shows.