Time is the most deceptively complicated thing in programming. It seems straightforward until you have users in different time zones, daylight saving transitions, and databases that store dates in three different formats. I have lost count of the off-by-one-hour bugs I have tracked down over the years, and every single one came from a misunderstanding of how time actually works in software.
What is a Unix Timestamp?
A Unix timestamp is simply the number of seconds that have elapsed since January 1, 1970, at 00:00:00 UTC. That specific moment is called the "Unix epoch." Right now, the current timestamp is a 10-digit number somewhere around 1.7 billion.
1711584000 = March 28, 2024 00:00:00 UTC
0 = January 1, 1970 00:00:00 UTC
-1 = December 31, 1969 23:59:59 UTC
The beauty of timestamps is that they are completely unambiguous. The number 1711584000 means the exact same moment everywhere on Earth. There is no timezone confusion, no daylight saving ambiguity, no date format debate. It is just a number.
This is why APIs and databases commonly use timestamps for storing dates. The human-readable conversion happens only at the display layer, when you need to show the time to a user in their local timezone.
UTC: The Reference Point
UTC (Coordinated Universal Time) is the baseline time standard that all time zones are defined relative to. It does not observe daylight saving time, which makes it stable and predictable. When someone says "the server runs on UTC," they mean the clock never jumps forward or backward.
A common mistake is treating UTC and GMT as interchangeable. They usually show the same time, but they are different things. GMT is a time zone (used in the UK during winter). UTC is a time standard. For programming purposes, always use UTC.
Time Zones Are Not Fixed Offsets
This is where most developers get tripped up. You might think "New York is UTC-5" and hardcode that offset. But New York is UTC-5 only during winter (Eastern Standard Time). During summer, it shifts to UTC-4 (Eastern Daylight Time). And the exact dates of the switch change based on legislation.
The IANA timezone database (also called the tz database or Olson database) tracks all of these rules. Instead of storing offsets, store timezone identifiers like "America/New_York" or "Asia/Tokyo." Your programming language's date library will handle the offset calculation correctly, including historical changes.
// Correct: use timezone names
"America/New_York" // handles DST automatically
"Europe/London" // handles GMT/BST automatically
// Risky: hardcoded offsets
"UTC-5" // wrong during DST
Seconds vs Milliseconds
Unix timestamps are traditionally in seconds, but JavaScript's Date.now() returns milliseconds. This is one of the most common sources of bugs when working across systems. A timestamp of 1711584000 (seconds) represents March 2024. Multiply by 1000 accidentally and you get a date in the year 56000+.
Always check what unit a timestamp is in. If the number has 10 digits, it is seconds. If it has 13 digits, it is milliseconds. Some systems (like Java's Instant) can even use nanoseconds.
ISO 8601: The Standard Date Format
If you need to represent a date as a string, use ISO 8601. It looks like this: 2026-03-28T14:30:00Z. The "T" separates date and time, the "Z" means UTC. You can also specify an offset: 2026-03-28T23:30:00+09:00 for the same moment in Tokyo.
ISO 8601 sorts correctly as a string, is unambiguous about month vs. day ordering (unlike "03/04/2026" which could be March 4th or April 3rd depending on your locale), and is supported by every major programming language's date parser.
The Year 2038 Problem
Unix timestamps stored as 32-bit signed integers will overflow on January 19, 2038. The maximum value a 32-bit signed integer can hold is 2,147,483,647, which corresponds to 03:14:07 UTC on that date. After that, the number wraps to negative, and the system thinks it is December 1901.
Most modern systems already use 64-bit integers for timestamps, which pushes the overflow date to approximately 292 billion years from now. But legacy embedded systems, old databases, and some programming languages still have 32-bit timestamp issues. If you are building something that needs to work past 2038, make sure your timestamp storage is 64-bit.
Practical Rules I Follow
- Store in UTC, display in local time. Keep all server-side timestamps in UTC. Convert to the user's local timezone only when rendering the UI.
- Use timezone names, not offsets. Store "America/Los_Angeles" instead of "UTC-8" so daylight saving transitions are handled correctly.
- Be explicit about units. Name your variables and database columns clearly:
created_at_unix_secondsis much clearer thancreated_at. - Test with time zone edge cases. Test your app with users in UTC+12, UTC-12, and UTC+5:30 (India uses a half-hour offset). Also test during daylight saving transitions.
- Never calculate time differences manually. Use your language's date library. There are too many edge cases -- leap seconds, DST transitions, varying month lengths -- for manual arithmetic to be reliable.