Unix Timestamp Guide: Precision, Timezone & DST Best Practices
Learn Unix timestamps: epoch origins, seconds/milliseconds/microseconds conversion, timezone handling, DST pitfalls, and code examples in JavaScript, Python, and Go.
Unix Timestamp Complete Guide: Seconds/Milliseconds/Microseconds Conversion & Timezone Best Practices
Unix timestamps represent time as “the amount elapsed since the Unix epoch (January 1, 1970, 00:00:00 UTC).” Over 95% of web servers and 90% of database systems globally use this representation internally. This guide covers precision differences, programming language implementations, timezone handling, and daylight saving time considerations.
Unix Timestamp Origins and Definition
The Unix Epoch began on January 1, 1970, 00:00:00 UTC. Unix timestamp 0 corresponds to this moment, while 1262304000 represents 2010-01-01 00:00:00 UTC. The system ignores the effects of leap seconds by default.
Originally stored as 32-bit signed integers, this created the Year 2038 Problem — the maximum value overflows on January 19, 2038, 03:14:07 UTC. Modern systems use 64-bit integers, extending representable timeframes significantly.
Time Precision Differences
| Unit | Count per Second | Digits | Typical Applications |
|---|---|---|---|
| Seconds (s) | 1 | 10 | Traditional Unix/Linux systems |
| Milliseconds (ms) | 1,000 | 13 | JavaScript, Java, logging |
| Microseconds (μs) | 1,000,000 | 16 | Distributed tracing, databases |
| Nanoseconds (ns) | 1,000,000,000 | 19 | Go language, performance analysis |
Practical rule: 10-digit timestamps generally represent seconds, 13 digits represent milliseconds, 16 digits represent microseconds, and 19 digits represent nanoseconds.
JavaScript Timestamps
JavaScript uses milliseconds natively. The Date() constructor assumes input numbers are milliseconds — for second-level timestamps, multiply by 1000.
// Get current Unix timestamp (in milliseconds)
const timestampMs = Date.now();
console.log(timestampMs); // Example output: 1692268800123
// For second-level timestamps, divide milliseconds by 1000 and round down
const timestampSec = Math.floor(Date.now() / 1000);
console.log(timestampSec); // Example output: 1692268800
// Convert Unix timestamp back to Date object
let ts = 1692268800;
let date = new Date(ts * 1000);
console.log(date.toISOString()); // "2023-08-17T16:00:00.000Z"
Python Timestamps
Python’s time.time() returns second-level Unix timestamps as floating-point values:
import time
from datetime import datetime, timezone
# Get current Unix timestamp (seconds, float)
now_sec = time.time()
print(now_sec) # Example output: 1692268800.123456
# Get milliseconds (integer)
now_millis = int(time.time() * 1000)
print(now_millis) # Example: 1692268800123
# Get nanoseconds (Python 3.7+)
now_nanos = time.time_ns()
print(now_nanos) # Example: 1692268800123456789
# Convert to datetime
ts = 1692268800
dt_local = datetime.fromtimestamp(ts)
dt_utc = datetime.fromtimestamp(ts, timezone.utc)
print(dt_local.strftime("%Y-%m-%d %H:%M:%S")) # Local time
print(dt_utc.strftime("%Y-%m-%d %H:%M:%S")) # UTC time
Go Language Timestamps
Go’s time library provides multiple precision levels:
package main
import (
"fmt"
"time"
)
func main() {
// Get current Unix timestamp
sec := time.Now().Unix() // Seconds
msec := time.Now().UnixMilli() // Milliseconds (Go 1.17+)
nsec := time.Now().UnixNano() // Nanoseconds
fmt.Println(sec) // Example: 1692268800
fmt.Println(msec) // Example: 1692268800123
fmt.Println(nsec) // Example: 1692268800123456789
// Convert timestamp to Time object
t := time.Unix(sec, 0)
fmt.Println(t.UTC())
fmt.Println(t)
}
Common Errors and Best Practices
Error Example: Unclear Units
// ✗ Wrong: unclear timestamp unit
const timestamp = 1692268800;
const date = new Date(timestamp); // Error: treated as milliseconds, shows 1970
// ✓ Correct: clearly indicate units
const timestampSec = 1692268800;
const timestampMs = 1692268800000;
const dateFromSec = new Date(timestampSec * 1000);
Field Naming Best Practice
log_entry = {
"timestamp_ms": 1692268800123, # Millisecond-level
"timestamp_iso": "2023-08-17T16:00:00Z", # ISO 8601 UTC
"event_type": "user_login",
"user_id": 12345
}
Timezone Handling Pitfalls
There are four main pitfalls when working with timezones:
- Confusing local time and UTC time — Unix timestamps are always UTC-based; convert to local only at display time
- Not saving timezone information — Creates ambiguity; always store UTC or include offset
- Cross-system timezone inconsistencies — All systems should use the same timezone reference (recommend UTC)
- Manually calculating DST offsets — Rely on built-in libraries, don’t hardcode
The recommended approach: “Standardized storage, localized display.” Use UTC or Unix timestamps in storage and transmission phases to ensure consistency; format according to user timezone when displaying.
Daylight Saving Time (DST) Issues
DST creates two problematic periods:
- Skipped time: When DST begins, clocks jump forward. For example, 02:00 jumps directly to 03:00, making 02:30 nonexistent.
- Repeated time: When DST ends, 01:00–01:59 appears twice, creating ambiguity.
Unix timestamps themselves remain continuous and unaffected by DST, but local time conversions require careful handling.
Best Practices for Logging, Databases, and APIs
Logging Systems
Unify UTC timezone + ISO 8601 format; include millisecond timestamps or microsecond precision when necessary.
Databases
Prefer native calendar types with timezone; use BIGINT for numeric timestamps with clear unit indication in field names (e.g., *_epoch_ms).
APIs
Clearly specify formats and units. External interfaces should use ISO 8601 (readable, includes timezone); internal systems can use numeric timestamps with documented units.
Common Error Scenarios
- 13-digit parsing failure: Millisecond timestamps fed to second-expecting functions cause overflow. Determine units by digit count first.
- Format mismatches: Invalid dates, missing timezones, or DST switching points cause parsing errors.
- Timezone offsets: Whole-hour deviations (±8h) typically indicate unification issues. Recommend using UTC internally.
- Numerical overflow: 32-bit systems face 2038 limits; prioritize 64-bit integers.
Frequently Asked Questions
Why January 1, 1970?
Unix operating system development began in 1970, and it was a round decade year — easy to remember and calculate. 32-bit integers could represent dates from 1970 to 2038, which was sufficient at the time.
How to identify seconds vs. milliseconds?
Three methods: check digit count (10 digits = seconds, 13 = milliseconds, 16 = microseconds, 19 = nanoseconds), calculate verification by parsing and checking reasonableness, or use online conversion tools.
Does the 2038 problem still matter?
Modern systems using 64-bit integers have largely resolved this. Mainstream programming languages already support 64-bit timestamps. Legacy 32-bit systems and embedded devices may still need attention.
Why does DST cause problems?
Time discontinuity from skipped hours and time repetition from repeated hours create parsing ambiguity. Different systems handle ambiguous times with different strategies. Solution: use UTC internally, convert to local time only at display.
Why do JavaScript and Python timestamps differ?
JavaScript’s Date.now() returns milliseconds (13 digits); Python’s time.time() returns seconds (floating-point with microsecond precision). Conversion requires dividing/multiplying by 1000.
Latest Trends and Future Outlook
- Higher precision: Financial trading, IoT, and real-time systems demand nanosecond-level accuracy
- Distributed synchronization: NTP and PTP protocols improve accuracy
- Blockchain timestamps: Cryptocurrency requires tamper-resistant, high-precision timestamps
- Performance optimization: SIMD instructions, memory caching, and parallel processing accelerate conversions
Summary
This comprehensive guide covers Unix timestamp essentials — from epoch origins and multi-precision conversions to cross-language implementations, timezone handling, DST pitfalls, and engineering best practices in logging, databases, and API design. The key takeaway: store in UTC, display in local time, and always be explicit about timestamp units.