Time is deceptively complex in software. At first glance, a timestamp is just a number or a formatted string — how hard can it be? The answer becomes clear the first time your server processes an event that arrives 5 hours late because a timezone wasn't accounted for, or when your scheduled job runs twice because of a daylight saving time transition, or when a date stored without timezone information becomes ambiguous after a server migration. Time handling is the source of more subtle production bugs than almost any other domain. This guide provides the complete conceptual foundation for working with time correctly in software.
Unix Time: The Foundation
Unix time (also called POSIX time, Unix epoch time, or simply a Unix timestamp) is a system for describing points in time as the number of seconds elapsed since 00:00:00 UTC on 1 January 1970 — an arbitrary reference point chosen when Unix was designed. A Unix timestamp is timezone-agnostic by definition: it represents a specific absolute moment in time, regardless of what timezone the reader is in. This is its fundamental advantage: a Unix timestamp stored in one timezone will be interpreted identically in any other timezone.
Modern systems typically work in milliseconds (thousandths of a second) rather than whole seconds, to accommodate the sub-second timing requirements of modern APIs, distributed systems, and analytics. JavaScript's Date.now() returns milliseconds since the epoch. When you see a large integer like 1738598400000, you are looking at a JavaScript millisecond timestamp. Divide by 1000 to get the equivalent seconds-based Unix timestamp.
The Unix epoch was not intended to represent dates before 1970. Negative timestamps represent dates before 1970, which most systems support, but behaviour varies. Very large timestamps (representing far-future dates) may also cause issues in systems that store timestamps as 32-bit signed integers — which leads to the Y2K38 problem.
The Year 2038 Problem (Y2K38)
32-bit signed integers can store values up to 2,147,483,647. When used to store Unix timestamps in seconds, this maximum value corresponds to 03:14:07 UTC on 19 January 2038. At that moment, systems using 32-bit signed integers for timestamps will overflow and roll over to the minimum negative value, typically representing 13 December 1901 — a catastrophic backwards jump that will break date calculations, logging, session expiration, and any other time-dependent logic.
The fix is straightforward: store timestamps as 64-bit integers. A 64-bit signed integer can represent timestamps up to approximately 292 billion years in the future — well beyond any practical concern. Most modern languages and databases default to 64-bit timestamps, but legacy systems (embedded software, older database schemas, C programs compiled for 32-bit targets) may still be vulnerable. If you're auditing a legacy system, check the integer width used for timestamp storage.
ISO 8601: The International Standard for Date-Time Strings
ISO 8601 is an international standard for representing dates and times as human-readable strings. It establishes a specific format that eliminates ambiguity between regional conventions — particularly the confusion between MM/DD/YYYY (United States) and DD/MM/YYYY (most of the world), which has caused real-world incidents including medical dosage errors and misrouted financial transactions.
The basic ISO 8601 date format is YYYY-MM-DD: a four-digit year, two-digit month (01–12), two-digit day (01–31), separated by hyphens. The time component extends this: YYYY-MM-DDTHH:MM:SS, where the T separator distinguishes the date from the time. The 24-hour clock is used: hours from 00 to 23, minutes and seconds from 00 to 59.
Fractional seconds are appended with a decimal point: 2025-02-27T14:30:00.000. Timezone designations are appended at the end: Z for UTC (the letter Z stands for "Zulu time," a NATO phonetic for UTC); +HH:MM or -HH:MM for UTC offsets. A complete, unambiguous ISO 8601 timestamp looks like 2025-02-27T14:30:00.000Z (UTC) or 2025-02-27T19:30:00.000+05:00 (Pakistan Standard Time, UTC+5).
Timezones: The Hard Part
A timezone is not simply a fixed offset from UTC. Timezones are political and geographic zones that share a civil time, and they change over time due to legislation — countries adopt daylight saving time (DST), abolish it, change their UTC offset, or rename their timezone. The IANA Time Zone Database (also called the Olson database or tzdata) is the authoritative source for timezone rules, updated multiple times per year as governments change their timezone policies.
Daylight Saving Time is the most common source of timezone bugs. Twice per year, clocks in DST-observing regions shift forward or backward by one hour. This creates two anomalous periods: a "spring forward" gap where times between 01:00 and 02:00 do not exist (clocks jump from 01:59 to 03:00), and a "fall back" overlap where times between 01:00 and 02:00 occur twice (clocks set back from 02:00 to 01:00). Scheduled jobs, recurring events, and interval calculations that cross these boundaries require careful handling.
The correct engineering approach is to store all timestamps in UTC and convert to local time only for display. UTC never observes DST, never changes its offset, and never creates ambiguous times. If you store a timestamp as "2025-03-09 01:30:00 America/New_York" without UTC conversion, you have a problem: that local time either doesn't exist (during spring-forward) or is ambiguous (during fall-back). If you store it as a UTC timestamp, you have an unambiguous reference that survives timezone policy changes.
JavaScript Date Handling
JavaScript's built-in Date object is infamous for its poor design, inherited from Java's early date APIs. Despite its flaws, understanding its behaviour is essential. new Date() creates a Date object representing the current moment. new Date(timestamp) accepts a millisecond Unix timestamp. new Date('2025-02-27T14:30:00.000Z') parses an ISO 8601 string. Date.now() returns the current millisecond timestamp without creating a Date object.
The critical gotcha: new Date('2025-02-27') (a date-only ISO string without time or timezone) is interpreted as UTC midnight in modern browsers, but was historically interpreted as local midnight in older environments. new Date('02/27/2025') (a US-format date string) is implementation-defined and will produce different results in different environments. Always use ISO 8601 strings with explicit timezone designations when constructing Date objects from strings.
The Intl.DateTimeFormat API provides locale-aware, timezone-aware date formatting: new Intl.DateTimeFormat('en-US', {timeZone: 'Asia/Karachi', dateStyle: 'full', timeStyle: 'long'}).format(new Date()). This uses the IANA timezone database built into the JavaScript engine and handles DST transitions correctly. It is the correct way to display dates in user-local timezones in a JavaScript application.
The Temporal API: The Future of JavaScript Dates
The Temporal API (TC39 Stage 3 proposal) is a comprehensive replacement for the JavaScript Date object that fixes all of its known design flaws. It provides distinct object types for different temporal concepts: Temporal.Instant for absolute moments in time (equivalent to Unix timestamps), Temporal.ZonedDateTime for time-zone-aware datetimes, Temporal.PlainDate for calendar dates without time, and more. It handles DST transitions correctly, provides consistent parsing, and has an immutable, method-based API.
Temporal is available in polyfill form and is expected to ship in all major browsers without a flag in the next few years. New projects building significant date-handling logic should evaluate whether using the polyfill now and migrating when the API lands is preferable to building on the legacy Date object.
Using Our Timestamp Converter
Our free Timestamp Converter tool converts between Unix timestamps (both seconds and milliseconds) and human-readable ISO 8601 dates in both directions, with millisecond precision. It handles timezone offset display and is useful for debugging log events, API responses, database records, and any situation where you encounter a Unix timestamp and need to understand what actual date and time it represents. All calculations happen in your browser — no data is sent to any server.
When debugging a production incident, having a quick timestamp converter readily accessible accelerates log analysis significantly. Being able to immediately translate 1740661800 to 2025-02-27T14:30:00Z — or the reverse — removes a friction point that compounds across a long debugging session. Bookmark the tool and add it to your developer toolbox alongside your browser devtools and API testing client.