Expert ReviewedUpdated 2025utility
utility
10 min readMay 1, 2025Updated Feb 17, 2026

Unix Timestamps & Date Handling: A Developer's Complete Reference

Master timestamps, time zones, and date parsing. Learn Unix epoch time, ISO 8601 formats, JavaScript Date APIs, and how to avoid common datetime bugs.

Few things cause more bugs than dates and times. Time zones shift, daylight saving confuses calculations, and different systems use different formats. This guide cuts through the complexity. You'll learn how timestamps work, when to use which date format, and how to handle the edge cases that break production systems.

Key Takeaways

  • 1
    Unix timestamps count seconds since January 1, 1970 UTC; JavaScript uses milliseconds
  • 2
    Always use ISO 8601 format (YYYY-MM-DDTHH:mm:ssZ) for APIs and data storage
  • 3
    Store dates in UTC; convert to local time only for display
  • 4
    JavaScript months are 0-indexed (January = 0)—a common source of bugs
  • 5
    Time zone ≠ offset: use IANA names (America/New_York) for proper DST handling

What Is a Unix Timestamp?

A Unix timestamp (also called epoch time or POSIX time) counts the seconds since January 1, 1970, 00:00:00 UTC. This "Unix Epoch" is the universal reference point for computer time.
Example: Timestamp Breakdown

Scenario

Convert a human-readable date to Unix timestamp

Solution

January 1, 2025 00:00:00 UTC = 1735689600 seconds since epoch. That's 55 years × 365.25 days × 24 hours × 60 minutes × 60 seconds (approximately).

Timestamp precision formats
FormatExampleWhen to Use
Seconds (Unix)1735689600APIs, databases, most backends
Milliseconds (JS)1735689600000JavaScript Date, modern APIs
Microseconds1735689600000000High-precision logging
Nanoseconds1735689600000000000Performance profiling
Why 1970? Unix was developed in the early 1970s, and choosing January 1, 1970 gave a convenient, round starting point. The 32-bit overflow (Y2K38 problem) happens January 19, 2038 at 03:14:07 UTC.

Date Formats: ISO 8601 vs Others

ISO 8601 is the international standard for date/time representation. Use it whenever possible—it's unambiguous, sortable, and widely supported.
Common date formats
FormatExampleNotes
ISO 8601 (full)2025-01-25T14:30:00ZBest for APIs and storage
ISO 8601 (offset)2025-01-25T14:30:00+05:30Includes timezone offset
ISO 8601 (date only)2025-01-25When time doesn't matter
RFC 2822Sat, 25 Jan 2025 14:30:00 +0000Email headers
US format01/25/2025Ambiguous—avoid in code
EU format25/01/2025Ambiguous—avoid in code
Never use MM/DD/YYYY or DD/MM/YYYY in APIs or data exchange. Is 01/02/2025 January 2nd or February 1st? ISO 8601 (YYYY-MM-DD) eliminates this ambiguity.
The "Z" in ISO 8601 (2025-01-25T14:30:00Z) means "Zulu time" = UTC. It's equivalent to +00:00 offset.

JavaScript Date Handling

JavaScript's Date object uses milliseconds since epoch internally. Understanding its quirks helps avoid common bugs.
Common JavaScript Date operations
OperationCodeResult
Current timestamp (ms)Date.now()1735689600000
Current timestamp (s)Math.floor(Date.now() / 1000)1735689600
Parse ISO stringnew Date("2025-01-25T14:30:00Z")Date object (UTC)
To ISO stringdate.toISOString()"2025-01-25T14:30:00.000Z"
From timestampnew Date(1735689600000)Date object
To timestampdate.getTime()1735689600000
JavaScript months are 0-indexed! new Date(2025, 0, 25) is January 25, not month 0. new Date(2025, 1, 25) is February 25. This causes countless bugs.
Example: Parsing Dates Safely

Scenario

Parse a date string from user input or API

Solution

Always use ISO format or explicit parsing. new Date("2025-01-25") may be interpreted as UTC or local time depending on browser. Safer: new Date("2025-01-25T00:00:00Z") for UTC, or use a library like date-fns.

Time Zones: The Hard Part

Time zones are where datetime handling gets truly complex. There are 37+ standard offsets, plus daylight saving rules that change by country and year.
  • **Store in UTC** – Always store timestamps in UTC. Convert to local time only for display.
  • **Offset ≠ Time Zone** – +05:30 is an offset; "Asia/Kolkata" is a time zone. Zones handle DST; offsets don't.
  • **Use IANA names** – "America/New_York" not "EST". EST doesn't account for EDT (daylight saving).
  • **Beware DST transitions** – Some times don't exist (clocks skip forward) or occur twice (clocks fall back).
  • **Date-only values** – "2025-01-25" with no time? Store as-is or as midnight UTC. Document your choice.
Timezone storage strategies
ApproachProsCons
Store as UTC timestampUnambiguous, sortableNeed timezone for local display
Store with offsetPreserves original contextOffset may be obsolete (DST change)
Store with timezone nameHandles future DSTRequires timezone database
JavaScript's Intl.DateTimeFormat and Temporal API (Stage 3) handle time zones properly. For older code, libraries like Luxon or date-fns-tz are essential.

5Common Datetime Bugs

These bugs appear in production constantly. Recognizing the patterns helps you catch them in code review.
Datetime bugs and solutions
BugCauseFix
Off-by-one monthJS months are 0-indexedUse ISO strings or libraries
Midnight timezone shiftnew Date("2025-01-25") parsed as UTCAlways include time and zone
Events on wrong dayStored UTC, displayed wrong zoneConvert with user's timezone
Daylight saving gaps2:30 AM doesn't exist during spring forwardUse libraries that handle DST
Leap year miscalculationFeb 29 doesn't always existUse proper date math, not day+365
Comparing dates as strings"2025-1-5" < "2025-12-1" is wrongCompare timestamps or Date objects
Example: The Timezone Shift Bug

Scenario

User in India (UTC+5:30) selects January 25. You store new Date("2025-01-25"). Later, user sees January 24.

Solution

The date was parsed as 2025-01-25T00:00:00 UTC. In IST, that's 2025-01-25T05:30:00, but if displayed without timezone awareness, it might show the previous day. Fix: Store with explicit timezone or as a date-only string.

Date Math & Comparisons

Adding days, calculating differences, and comparing dates all have gotchas. Here's how to do it correctly.
Date operations
OperationApproachNote
Add daysdate.setDate(date.getDate() + n)Handles month overflow correctly
Add monthsdate.setMonth(date.getMonth() + n)May shift day (Jan 31 + 1 month = ?)
Difference in days(date2 - date1) / 86400000Result in milliseconds, divide by ms/day
Compare datesdate1.getTime() < date2.getTime()Compare timestamps, not Date objects
Same day checkCompare year, month, date individuallyOr truncate to midnight and compare
Adding months is tricky. January 31 + 1 month = March 3 (or Feb 28/29 depending on implementation). Libraries like date-fns have addMonths that clamps to end of month.

Convert Timestamps Instantly

Use our free Timestamp Converter to translate between Unix time and human-readable dates with timezone support.

Open Timestamp Converter

7Dates in APIs & Databases

How you send and store dates affects your entire system. Here are best practices for different contexts.
Date formats by context
ContextRecommended FormatExample
REST API request/responseISO 8601 string"createdAt": "2025-01-25T14:30:00Z"
GraphQLISO 8601 or custom scalarDateTime scalar type
SQL databasesTIMESTAMP WITH TIME ZONEPostgreSQL, MySQL datetime
NoSQL (MongoDB)ISODate or timestampISODate("2025-01-25T14:30:00Z")
RedisUnix timestamp (seconds)EXPIREAT key 1735689600
Message queuesUnix timestamp (ms)Compact, language-agnostic
For APIs, document your timezone policy. State whether timestamps are UTC, whether date-only fields include time, and how DST is handled.

8Date Libraries: When to Use Them

Native Date APIs are improving, but libraries still solve real problems. Here's when each option makes sense.
Date library comparison
LibrarySizeBest For
Native Date0 KBSimple cases, modern browsers
date-fns~13 KB (tree-shake)Functional approach, modular
Luxon~70 KBFull timezone support, immutable
Day.js~2 KB + pluginsMoment.js replacement, small
Temporal (proposal)0 KB (native)Future standard, use polyfill now
Moment.js is in maintenance mode. For new projects, use date-fns (tree-shakeable), Day.js (tiny), or Luxon (full timezone support). Watch for the Temporal API to become standard.
  • **Use native Date** when: Parsing ISO strings, getting current time, simple formatting
  • **Use a library** when: Complex timezone logic, recurring events, relative time ("3 days ago")
  • **Consider Temporal** when: Starting new projects, can use polyfill, need precision

Frequently Asked Questions

What's the difference between Unix timestamp and JavaScript timestamp?
Unix timestamps count seconds since epoch (January 1, 1970 UTC). JavaScript uses milliseconds. To convert: JS to Unix = Math.floor(jsTimestamp / 1000). Unix to JS = unixTimestamp * 1000. APIs often expect seconds; JavaScript Date expects milliseconds.
How do I handle dates without times (birthdays, holidays)?
Store date-only values as strings (YYYY-MM-DD) or as midnight UTC. Document your choice. The problem: "2025-01-25" can become January 24 or 25 depending on timezone. For birthdays, storing as string often makes more sense than a timestamp.
Why does my date show the wrong day across timezones?
You're likely storing a UTC timestamp but displaying in local time (or vice versa). Example: Midnight UTC on January 25 is 7:30 PM on January 24 in New York (EST). Fix: Always be explicit about timezones when storing and displaying.
How do I calculate the difference between two dates in days?
Subtract the timestamps and divide by milliseconds per day: (date2.getTime() - date1.getTime()) / (1000 * 60 * 60 * 24). For calendar days (ignoring time), set both dates to midnight first or use a library like date-fns differenceInDays.
What's the Y2K38 problem?
On January 19, 2038 at 03:14:07 UTC, a 32-bit signed Unix timestamp overflows. It will wrap to -2147483648, representing December 13, 1901. Modern systems use 64-bit timestamps which won't overflow for 292 billion years. Legacy systems may need updates.