Unix Timestamp Converter: Epochs, Timezones, 2038

9 min17 de maio de 2026

What a Unix Timestamp Converter Does (And Why You Need One)

A unix timestamp converter translates between human-readable dates and the number of seconds since January 1, 1970 00:00:00 UTC (the "Unix epoch"). Right now, as I write this, the timestamp is approximately 1,780,000,000. That number increases by 1 every second, never resets, and doesn't care about timezones, daylight saving, or leap years. It's the simplest possible way to represent a moment in time.

Why do developers need a converter? Because humans think in "June 4, 2026 at 3:30 PM" and computers think in 1780646400. Every API, database, and log file uses one format or the other (or both). Converting between them by hand requires knowing the timezone offset, whether DST is active, and how many seconds are in each month. Or you can just use a converter tool and get the answer in milliseconds.

The Unix epoch (January 1, 1970) was chosen arbitrarily by the creators of Unix at Bell Labs. It has no astronomical or historical significance. Other systems use different epochs: Windows FILETIME counts 100-nanosecond intervals since January 1, 1601. macOS Cocoa counts seconds since January 1, 2001. GPS time counts weeks and seconds since January 6, 1980. Converting between these requires knowing both the epoch and the unit.

Seconds vs Milliseconds (The #1 Source of Bugs)

Unix timestamps traditionally count seconds. JavaScript's Date.now() returns milliseconds. Java's System.currentTimeMillis() returns milliseconds. Python's time.time() returns seconds (as a float). This inconsistency causes bugs constantly. If you see a timestamp of 1780646400, it's seconds (June 2026). If you see 1780646400000, it's milliseconds (same moment). If you accidentally treat milliseconds as seconds, you get a date in the year 58,400.

The quick check: if the number has 10 digits, it's seconds (valid from 2001 to 2286). If it has 13 digits, it's milliseconds (valid from 2001 to 2286). If it has 16 digits, it's microseconds (Python's datetime.timestamp() with microsecond precision). Our timestamp-converter tool auto-detects the unit based on the number of digits.

My rule: always store timestamps in milliseconds (or the ISO 8601 string format). Milliseconds give you sub-second precision without the floating-point issues of fractional seconds. Every modern language can handle 64-bit integers, so the storage cost is the same. When interfacing with APIs that use seconds, multiply/divide by 1000 at the boundary — don't let mixed units propagate through your codebase.

A bug I hit in 2021: a payment system stored "created_at" in seconds but the webhook verification checked "timestamp is within 5 minutes of now" using milliseconds. The check always failed because the difference was 1,780,000,000,000 milliseconds (the timestamp in seconds, interpreted as milliseconds = year 58,400) minus the current time. It took 3 hours to find because the error message just said "timestamp expired."

Timezone Bugs That Hit Every Developer

The most common timezone bug: storing local time without timezone information. If your database has "2026-06-04 15:30:00" — is that UTC? Eastern time? The server's timezone? If the server moves to a different timezone (or you migrate to a cloud region), all your timestamps shift. Always store UTC and convert to local time only for display.

Daylight Saving Time creates impossible and ambiguous times. On November 3, 2024 at 2:00 AM Eastern, clocks fell back to 1:00 AM. The time "1:30 AM" happened twice. On March 10, 2024 at 2:00 AM, clocks jumped to 3:00 AM. The time "2:30 AM" never existed. If your scheduling system creates an event at 2:30 AM on a spring-forward day, what happens? Most systems silently shift it to 3:30 AM. Some crash.

The "day boundary" bug: "today's orders" means different things in different timezones. If your server is in UTC and a user in California places an order at 11 PM Pacific (7 AM UTC next day), it shows up in "tomorrow's" report. Fix: always filter by the user's local day boundaries converted to UTC. Store the user's timezone (IANA format like "America/Los_Angeles", not UTC offsets which don't account for DST).

JavaScript's Date object is timezone-aware but confusing. new Date("2026-06-04") is parsed as UTC midnight, but new Date("2026-06-04T00:00:00") is parsed as local time. new Date(2026, 5, 4) uses local time (and months are 0-indexed, so 5 = June). This inconsistency has caused more bugs than any other JavaScript API. Use the Temporal API (Stage 3, available in polyfills) or libraries like date-fns with explicit timezone handling.

// The timezone trap in JavaScript
new Date("2026-06-04");           // UTC midnight
new Date("2026-06-04T00:00:00"); // LOCAL midnight (different!)
new Date(2026, 5, 4);            // LOCAL midnight, month 5 = June

// Safe approach: always be explicit about timezone
new Date("2026-06-04T00:00:00Z");      // UTC (the Z matters)
new Date("2026-06-04T00:00:00+08:00"); // Beijing time

// Converting timestamp to readable date
const ts = 1780646400;
new Date(ts * 1000).toISOString();     // "2026-06-04T12:00:00.000Z"
new Date(ts * 1000).toLocaleString("en-US", {
  timeZone: "America/New_York"
}); // "6/4/2026, 8:00:00 AM"

The Year 2038 Problem (It's Real)

A signed 32-bit integer can hold values up to 2,147,483,647. That many seconds after the Unix epoch is January 19, 2038 at 03:14:07 UTC. After that moment, 32-bit timestamps overflow to negative numbers, wrapping around to December 13, 1901. This is the Y2K problem for Unix systems, and it's 12 years away.

What's affected: embedded systems (IoT devices, car computers, industrial controllers), older databases with 32-bit timestamp columns, C programs using time_t as a 32-bit int, and file formats that store 32-bit timestamps (ext3 filesystem, some ZIP implementations). Linux kernel switched to 64-bit time_t for 32-bit architectures in kernel 5.6 (2020), but user-space programs compiled against older libraries may still use 32-bit time.

What's NOT affected: any 64-bit system (all modern servers, desktops, and phones), JavaScript (uses 64-bit floats for timestamps), Python (arbitrary precision integers), Java (long is 64-bit), PostgreSQL (timestamp type is 64-bit). If you're writing a web application in 2026, you're almost certainly fine. The risk is in embedded systems and legacy code that won't be updated before 2038.

If you maintain legacy systems: audit your timestamp storage. MySQL's TIMESTAMP type was 32-bit until MySQL 8.0.28 (2022) — older versions will overflow in 2038. SQLite stores timestamps as text or 64-bit integers (safe). Check any C/C++ code that uses time_t — on 32-bit platforms, it may still be 32 bits. The fix is usually recompiling with _TIME_BITS=64 or migrating to 64-bit platforms.

Storing Timestamps in Databases

PostgreSQL: Use TIMESTAMPTZ (timestamp with time zone). Despite the name, it doesn't store a timezone — it stores UTC and converts to/from the session timezone on input/output. Plain TIMESTAMP (without time zone) stores whatever you give it with no conversion, which leads to ambiguity. Always use TIMESTAMPTZ.

MySQL: TIMESTAMP stores UTC (4 bytes, range 1970-2038 in older versions, extended in 8.0.28+). DATETIME stores the literal value without timezone conversion (8 bytes, range 1000-9999). Use TIMESTAMP for "when did this happen" (auto-converts to UTC) and DATETIME for "scheduled for this exact date/time regardless of timezone" (like a birthday or a meeting in a specific timezone).

MongoDB: The Date type stores milliseconds since epoch as a 64-bit integer. It's always UTC internally. The ISODate() shell helper is just syntactic sugar for new Date(). Store all dates as Date objects, not strings. String dates can't be indexed efficiently and comparison operators won't work correctly across timezones.

General advice: store UTC timestamps, store the user's timezone separately (as an IANA timezone string like "Asia/Tokyo"), and compute local display time in the application layer. Never store pre-formatted date strings — you lose the ability to re-format for different locales or recalculate when timezone rules change (which happens more often than you'd think — governments change DST rules regularly).

Leap Seconds (The Edge Case That Breaks Things)

Earth's rotation is slowing down, so UTC occasionally adds a "leap second" to stay synchronized with astronomical time. When this happens, the time 23:59:60 exists for one second before midnight. Unix timestamps handle this by either repeating a second (the clock shows the same timestamp twice) or "smearing" the leap second over a longer period (Google's approach: spread it over 24 hours so each second is slightly longer).

In practice, leap seconds have caused real outages. Reddit went down for 30 minutes during the June 2012 leap second because the Linux kernel's clock handling had a bug that caused high CPU usage. Cloudflare had a brief outage in January 2017 when their RRDNS software calculated a negative time duration during the leap second. These bugs are rare but spectacular.

The good news: the International Bureau of Weights and Measures (BIPM) voted in 2022 to abolish leap seconds by 2035. Until then, there are 27 leap seconds accumulated since 1972. Most modern systems use NTP (Network Time Protocol) which handles leap seconds transparently. If you're building a system that needs sub-second accuracy across leap second boundaries (financial trading, scientific instruments), use TAI (International Atomic Time) which doesn't have leap seconds.

For most developers: ignore leap seconds. Your language's standard library handles them (or pretends they don't exist, which is fine for 99.99% of applications). Don't try to account for them manually. The only time you'll notice is if you're computing exact durations across a leap second boundary and get 61 seconds in a "minute" — which is technically correct.

Practical Patterns for Working with Timestamps

Pattern 1: API responses. Return ISO 8601 strings with timezone offset: "2026-06-04T15:30:00+08:00" or UTC with Z suffix: "2026-06-04T07:30:00Z". Don't return bare Unix timestamps in user-facing APIs — they're unreadable without a converter. Internal service-to-service APIs can use millisecond timestamps for efficiency.

Pattern 2: Scheduling future events. Store the intended local time AND the timezone: {time: "2026-12-25T09:00:00", timezone: "America/New_York"}. Don't pre-convert to UTC because if the timezone rules change (government moves DST dates), your stored UTC time becomes wrong. Convert to UTC at execution time using the latest timezone database.

Pattern 3: Audit logs and event sourcing. Use monotonic timestamps (not wall-clock time) for ordering events within a single process. Wall clocks can jump backward (NTP corrections, VM migrations, leap seconds). For cross-machine ordering, use logical clocks (Lamport timestamps, vector clocks) or synchronized timestamps with bounded error (Google Spanner's TrueTime, AWS Time Sync).

Pattern 4: Age calculations. Don't subtract timestamps and divide by seconds-per-year (365.25 × 86400). This fails for leap years, DST transitions, and timezone differences. Use a proper date library that calculates calendar differences: date-fns differenceInYears(), Python's relativedelta, or our age-calculator tool which handles all these edge cases correctly.