datetimeunixtimezone

Unix Timestamps and Date/Time Tools: The Complete Guide

· Cosyslabs

A Unix timestamp is the number of seconds elapsed since the Unix epoch: January 1, 1970, 00:00:00 UTC. Timestamps are timezone-independent — the same integer represents the same moment everywhere on Earth. They are the standard way to store and compare datetimes in databases, APIs, and logs.

The Unix Epoch

Unix epoch: 1970-01-01T00:00:00.000Z

Current time (2026-06-15T12:00:00Z): 1,750,000,000 (approximately)

Range of 32-bit Unix timestamps:
  Min: -2,147,483,648  →  1901-12-13 20:45:52 UTC
  Max:  2,147,483,647  →  2038-01-19 03:14:07 UTC  (Year 2038 Problem)

Getting the Current Timestamp

// JavaScript — seconds
Math.floor(Date.now() / 1000)

// JavaScript — milliseconds (more common in JS ecosystem)
Date.now()

// JavaScript — nanoseconds (Node.js)
process.hrtime.bigint()
import time
from datetime import datetime, timezone

# Seconds (float)
time.time()

# Integer seconds
int(time.time())

# Milliseconds
int(time.time() * 1000)

# Using datetime
datetime.now(timezone.utc).timestamp()
# Linux/macOS shell
date +%s       # seconds
date +%s%3N    # milliseconds
-- PostgreSQL
SELECT EXTRACT(EPOCH FROM NOW())::BIGINT;
SELECT (EXTRACT(EPOCH FROM NOW()) * 1000)::BIGINT;

-- MySQL
SELECT UNIX_TIMESTAMP();
SELECT UNIX_TIMESTAMP() * 1000;

-- SQLite
SELECT strftime('%s', 'now');

Converting Timestamps to Dates

// Seconds to Date
new Date(1750000000 * 1000)
// Mon Jun 15 2026 ...

// Milliseconds to Date
new Date(1750000000000)

// Format options
const date = new Date(timestamp * 1000);
date.toISOString();          // "2026-06-15T12:00:00.000Z"
date.toLocaleDateString();   // locale-specific
date.toUTCString();          // "Mon, 15 Jun 2026 12:00:00 GMT"

// Intl.DateTimeFormat — full control
const formatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "full",
  timeStyle: "long",
  timeZone: "America/New_York",
});
formatter.format(date); // "Monday, June 15, 2026 at 8:00:00 AM EDT"
from datetime import datetime, timezone

# Seconds to datetime (always UTC-aware)
dt = datetime.fromtimestamp(1750000000, tz=timezone.utc)
# datetime(2026, 6, 15, 12, 0, tzinfo=timezone.utc)

dt.isoformat()  # "2026-06-15T12:00:00+00:00"

# Convert to specific timezone
from zoneinfo import ZoneInfo
eastern = dt.astimezone(ZoneInfo("America/New_York"))
# datetime(2026, 6, 15, 8, 0, tzinfo=ZoneInfo("America/New_York"))
import (
  "fmt"
  "time"
)

ts := int64(1750000000)
t := time.Unix(ts, 0).UTC()
fmt.Println(t.Format(time.RFC3339)) // "2026-06-15T12:00:00Z"

// Convert timezone
loc, _ := time.LoadLocation("America/New_York")
eastern := t.In(loc)

ISO 8601 Format

ISO 8601 is the international standard for date and time representation:

2026-06-15              date only
2026-06-15T12:00:00     local time (no timezone info — avoid in APIs)
2026-06-15T12:00:00Z    UTC (Z = Zulu = UTC)
2026-06-15T08:00:00-04:00  With UTC offset
2026-06-15T12:00:00.000Z   With milliseconds

Always include timezone information in API responses. A datetime string without timezone is ambiguous and causes bugs when clients are in different timezones.

// Good: always UTC in APIs
new Date().toISOString(); // "2026-06-15T12:00:00.000Z"

// Better: let the client convert to local time for display
// Store and transmit in UTC; display in user's local timezone

Timezone Handling

Timezones are the primary source of datetime bugs. Key rules:

  1. Store in UTC — always store datetimes as UTC in databases
  2. Display in local time — convert to user's timezone only for display
  3. Never store local time2026-06-15 08:00:00 without timezone is ambiguous
  4. Be aware of DST — offsets change twice a year in most regions
// WRONG — stores ambiguous local time
const appointment = new Date(2026, 2, 8, 2, 30); // 2:30 AM might not exist (DST)

// RIGHT — always use UTC
const appointment = new Date(Date.UTC(2026, 2, 8, 7, 30)); // 7:30 AM UTC = 2:30 AM EST

// Display in user's timezone
const formatter = new Intl.DateTimeFormat("en-US", {
  timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  dateStyle: "medium",
  timeStyle: "short",
});
formatter.format(appointment);

IANA Timezone Database

JavaScript's Intl API uses IANA timezone identifiers:

America/New_York    America/Chicago    America/Denver    America/Los_Angeles
Europe/London       Europe/Paris       Europe/Berlin     Europe/Moscow
Asia/Tokyo          Asia/Shanghai      Asia/Kolkata      Asia/Singapore
Australia/Sydney    Pacific/Auckland   America/Sao_Paulo Africa/Cairo

Avoid abbreviations like EST, PST — they are ambiguous (EST is used by multiple timezones) and not valid IANA identifiers.

Date Arithmetic

// Add days
const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);

// Add months (careful — months have different lengths)
const nextMonth = new Date(date);
nextMonth.setMonth(nextMonth.getMonth() + 1);

// Difference in days
const diffMs = date2.getTime() - date1.getTime();
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));

// Start of day in UTC
const startOfDay = new Date(date);
startOfDay.setUTCHours(0, 0, 0, 0);

// Start of week (Monday)
const dayOfWeek = date.getUTCDay(); // 0=Sun, 1=Mon, ...
const startOfWeek = new Date(date);
startOfWeek.setUTCDate(date.getUTCDate() - ((dayOfWeek + 6) % 7));
from datetime import datetime, timedelta, timezone
from dateutil.relativedelta import relativedelta  # pip install python-dateutil

now = datetime.now(timezone.utc)

# Add days
tomorrow = now + timedelta(days=1)

# Add months (handles month-length differences correctly)
next_month = now + relativedelta(months=1)

# Difference
diff = date2 - date1  # timedelta
diff.days
diff.total_seconds()

# Start of day
start = now.replace(hour=0, minute=0, second=0, microsecond=0)

The Year 2038 Problem

32-bit signed Unix timestamps overflow on January 19, 2038 at 03:14:07 UTC when the value reaches 2,147,483,647.

// 32-bit C code — will overflow in 2038
time_t t = time(NULL);  // time_t is often int32 on 32-bit systems

Affected systems:

  • 32-bit Linux systems using 32-bit time_t
  • Older embedded systems (industrial equipment, IoT devices)
  • Some database columns defined as INT storing Unix timestamps
  • Legacy C/C++ code on 32-bit platforms

Solutions:

  • Use 64-bit integers for timestamps (covers 292 billion years)
  • In SQL: use BIGINT instead of INT for timestamp columns
  • In PostgreSQL: TIMESTAMP WITH TIME ZONE handles this automatically
  • In MySQL: DATETIME column type is safe (stores as 8 bytes internally)
-- Bad (will overflow in 2038 on 32-bit systems)
created_at INT DEFAULT UNIX_TIMESTAMP()

-- Good
created_at BIGINT DEFAULT (UNIX_TIMESTAMP() * 1000)
-- or better
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

Common Date Formats

// ISO 8601 (recommended for APIs)
"2026-06-15T12:00:00.000Z"

// HTTP Date (RFC 7231 — used in headers)
"Mon, 15 Jun 2026 12:00:00 GMT"

// RFC 2822 (email)
"Mon, 15 Jun 2026 08:00:00 -0400"

// US format
"06/15/2026"

// European format (ambiguous with US!)
"15/06/2026"

// SQL date
"2026-06-15 12:00:00"

// Relative time
"2 hours ago"  // Do not store this — compute from timestamp

Database DateTime Best Practices

-- PostgreSQL: always use TIMESTAMPTZ (stores in UTC, displays in session timezone)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()

-- MySQL: use DATETIME or TIMESTAMP (TIMESTAMP auto-converts to UTC)
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
-- NOT: created_at INT -- avoid storing raw Unix timestamps in SQL

-- Index for time-range queries
CREATE INDEX idx_created_at ON events(created_at);

-- Query last 7 days
SELECT * FROM events
WHERE created_at > NOW() - INTERVAL '7 days';

Tools