What is a UNIX Timestamp?
A UNIX timestamp (also known as Epoch time or POSIX time) is the number of milliseconds that have elapsed since January 1, 1970 00:00:00 UTC.
It is the universal standard for tracking time in computing — compact, timezone-independent, and easy to compare.
Why milliseconds and not seconds?
The original UNIX standard measured time in seconds. Modern languages (JavaScript, Java) use milliseconds to achieve sub-second precision without floating-point arithmetic. Some systems (Linux clock_gettime, Go's time.Now().UnixNano()) go further with nanoseconds. Always check your language's default unit when working with timestamps.
What makes timestamps universal?
- No timezone ambiguity — always relative to UTC
- Single integer — easy to store, compare, and transmit
- Naturally sortable — larger value = later time
- No DST conversion ambiguity — wall clock times can be ambiguous, timestamps never are
System.currentTimeMillis() in Java
System.currentTimeMillis() is Java's built-in method that returns the current time as the number of milliseconds since January 1, 1970 UTC. It is the Java equivalent of JavaScript's Date.now().
public class TimestampExample {
public static void main(String[] args) {
// Get current time in milliseconds
long millis = System.currentTimeMillis();
System.out.println("Millis: " + millis);
// Convert to Date
java.util.Date date = new java.util.Date(millis);
System.out.println("Date: " + date);
// Modern API (Java 8+) — recommended
java.time.Instant instant = java.time.Instant.ofEpochMilli(millis);
System.out.println("Instant: " + instant);
}
}
Modern Java time API (recommended for Java 8+)
Java 8 introduced the java.time package which is vastly superior to the legacy Date/Calendar API.
import java.time.*;
// Current timestamp in milliseconds
long ms = Instant.now().toEpochMilli();
// Current timestamp in seconds
long sec = Instant.now().getEpochSecond();
// Convert millis back to Instant
Instant instant = Instant.ofEpochMilli(ms);
// Format as ISO 8601
String iso = instant.toString(); // "2026-03-16T10:30:00Z"
// Format with timezone
ZonedDateTime zdt = instant.atZone(ZoneId.of("America/New_York"));
String formatted = zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.nanoTime() vs currentTimeMillis()
System.nanoTime() returns nanoseconds elapsed since an arbitrary origin — it is not anchored to the UNIX epoch. Use it only for measuring elapsed time, not for wall-clock timestamps.
// Measure elapsed time (correct)
long start = System.nanoTime();
doSomething();
long elapsed = System.nanoTime() - start;
System.out.printf("Took %.2f ms%n", elapsed / 1_000_000.0);
// Wall clock (correct)
long now = System.currentTimeMillis();
Instant.now().toEpochMilli() from java.time for new code. It is immutable, thread-safe, and more expressive than System.currentTimeMillis().Understanding UTC
UTC (Coordinated Universal Time) is the primary time standard by which the world regulates clocks and time. It is the successor to Greenwich Mean Time (GMT) and is the foundation for all UNIX timestamps.
UTC vs GMT — What is the difference?
GMT (Greenwich Mean Time) is the original timezone based on mean solar time at the Royal Observatory in Greenwich, London. UTC is the modern standard based on atomic clocks. They share the same offset (UTC+0 = GMT+0), but UTC is more precise — it incorporates leap seconds to account for irregularities in Earth's rotation.
- In programming, UTC and GMT are interchangeable. Most databases, APIs, and systems store time in UTC.
- Leap seconds are added to UTC periodically (since 1972) — most computer systems "smear" or ignore them and do not expose them to application code.
Why store everything in UTC?
- Timezone rules change (governments adjust DST schedules). UTC never changes.
- Comparing timestamps across timezones is trivial — just compare UTC values directly.
- Daylight Saving Time (DST) transitions create ambiguous wall-clock times. UTC has no ambiguity.
- Databases (PostgreSQL, MySQL) with
TIMESTAMP WITH TIME ZONEstore values in UTC internally.
Getting UTC time in different languages
const now = new Date();
console.log(now.toUTCString()); // "Mon, 16 Mar 2026 10:30:00 GMT"
console.log(now.toISOString()); // "2026-03-16T10:30:00.000Z"
console.log(Date.now()); // ms since epoch (always UTC)
from datetime import datetime, timezone
# UTC-aware datetime
now_utc = datetime.now(timezone.utc)
print(now_utc.isoformat()) # "2026-03-16T10:30:00+00:00"
# Unix timestamp (seconds)
import time
ts = time.time() # float seconds
Working with Timezones
Timezones are one of the most common sources of bugs in software. Understanding how they work — especially Daylight Saving Time (DST) — saves hours of debugging.
Timezone offsets — how they work
A timezone is a region that observes a uniform standard time. Offsets are expressed as UTC+HH:MM or UTC-HH:MM relative to Coordinated Universal Time.
UTC+05:30= India Standard Time (IST) — 5 hours 30 minutes ahead of UTCUTC-05:00= Eastern Standard Time (EST)UTC+09:00= Japan Standard Time (JST) — no DST
+05:30. Use IANA timezone names (e.g. "Asia/Kolkata") because offsets can change due to political decisions.Daylight Saving Time (DST) explained
DST is the practice of advancing clocks by 1 hour during summer months to extend evening daylight. It is observed in many (but not all) countries.
Common DST pitfalls:
- Clocks "spring forward" — 2:00 AM becomes 3:00 AM. The 2–3 AM hour does not exist.
- Clocks "fall back" — 2:00 AM becomes 1:00 AM again. The 1–2 AM hour occurs twice.
- Events scheduled at ambiguous times may be mis-scheduled by exactly 1 hour.
// Safe: use Intl.DateTimeFormat with IANA timezone name
const now = new Date();
const fmt = new Intl.DateTimeFormat('en-US', {
timeZone: 'America/New_York',
dateStyle: 'full',
timeStyle: 'long'
});
console.log(fmt.format(now));
// "Monday, March 16, 2026 at 6:30:00 AM EDT"
Countries that do NOT observe DST
Many countries near the equator and some others do not observe DST, making their offset fixed year-round:
- Japan (UTC+9), China (UTC+8), India (UTC+5:30)
- Most of Africa, Southeast Asia, and the Middle East
- Arizona (USA), Hawaii (USA) — state-level exceptions within DST-observing countries
Common timezone traps in code
- Parsing dates without a timezone —
new Date("2026-03-16")in JavaScript is parsed as UTC midnight, butnew Date("03/16/2026")is parsed as local midnight. Always specify timezone explicitly. - Storing local time in the database — always store UTC, convert on output.
- Comparing timestamps across DST boundaries — always convert to UTC first.
- Scheduling recurring events — use IANA names, not offsets, so future DST transitions are handled automatically.
// DANGER: Different parsing behavior!
new Date("2026-03-16").toISOString();
// "2026-03-16T00:00:00.000Z" — UTC midnight ✓
new Date("03/16/2026").toISOString();
// "2026-03-16T05:00:00.000Z" — local midnight in UTC-5 !
// SAFE: always append time and Z for UTC
new Date("2026-03-16T00:00:00Z").toISOString();
// "2026-03-16T00:00:00.000Z" ✓
Timestamp Formats Explained
Many standards define how to write a timestamp as a human-readable string. Choosing the right format depends on your use case.
| Format | Example | Best For |
|---|---|---|
| ISO 8601 Recommended | 2026-03-16T10:30:00.000Z |
APIs, databases, log files, JSON payloads |
| RFC 3339 | 2026-03-16T10:30:00+00:00 |
Internet protocols, ATOM feeds — a strict profile of ISO 8601 |
| RFC 2616 (HTTP) | Mon, 16 Mar 2026 10:30:00 GMT |
HTTP headers (Last-Modified, Expires, Cookie) |
| Unix (seconds) | 1773835800 |
Storage, comparison, arithmetic — smallest representation |
| Unix (milliseconds) | 1773835800000 |
JavaScript, Java, sub-second precision |
| Julian Date | 2461110.9375 |
Astronomy, scientific calculations — days since Jan 1, 4713 BC |
ISO 8601 in depth
ISO 8601 is the international standard for date and time representation. Key components:
2026 - 03 - 16 T 10 : 30 : 00 . 000 Z
Year Month Day Hr Min Sec Ms UTC
With offset:
2026-03-16T10:30:00.000+07:00 (UTC+7)
2026-03-16T10:30:00.000-05:00 (UTC-5)
Date only:
2026-03-16
Week notation:
2026-W12-1 (Year-Week-Weekday)
Julian Date calculation
Julian Date (JD) is a continuous count of days since the beginning of the Julian Period (January 1, 4713 BC). The formula from a Unix timestamp (milliseconds) is:
// Julian Date from Unix milliseconds
julianDate = (unixMs / 86400000) + 2440587.5;
// Example: Jan 1, 1970 00:00:00 UTC
// (0 / 86400000) + 2440587.5 = 2440587.5
// JavaScript
const jd = (Date.now() / 86400000) + 2440587.5;
Common Timestamp Operations
Since timestamps are just numbers, arithmetic is straightforward. Here are the most common operations:
Adding / Subtracting time
const now = Date.now(); // ms
// Constants (in milliseconds)
const SECOND = 1000;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;
// Add 30 days
const in30Days = now + (30 * DAY);
// Subtract 2 hours
const twoHoursAgo = now - (2 * HOUR);
// Add 1 year (approximate — use date lib for exact)
const inOneYear = now + (365.25 * DAY);
30 * DAY always equals exactly 30 UTC days. However, if you need "1 calendar month from now", use a date library (date-fns, Luxon, Day.js) because months have variable lengths.Comparing timestamps
const ts1 = 1700000000000;
const ts2 = 1773835800000;
// Is ts1 before ts2?
ts1 < ts2; // true
// Difference in days
const diffDays = (ts2 - ts1) / (1000 * 60 * 60 * 24);
// Is a timestamp in the past?
const isExpired = ts1 < Date.now();
// Sort array of timestamps (ascending)
const sorted = [ts2, ts1, 1000000000000].sort((a, b) => a - b);
Date arithmetic — start/end of day, week, month
// Start of today (UTC midnight)
const now = new Date();
const startOfDay = new Date(
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
).getTime();
// Start of this month
const startOfMonth = new Date(
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)
).getTime();
// End of today (last ms)
const endOfDay = startOfDay + (24 * 60 * 60 * 1000) - 1;
Relative time formatting ("2 hours ago")
function relativeTime(ms) {
const diff = ms - Date.now();
const abs = Math.abs(diff);
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
if (abs < 60000) return rtf.format(Math.round(diff/1000), 'second');
if (abs < 3600000) return rtf.format(Math.round(diff/60000), 'minute');
if (abs < 86400000) return rtf.format(Math.round(diff/3600000), 'hour');
return rtf.format(Math.round(diff/86400000), 'day');
}
relativeTime(Date.now() - 7200000); // "2 hours ago"
relativeTime(Date.now() + 86400000); // "tomorrow"
Language Quick Reference
How to get the current time as milliseconds since the UNIX epoch in 30+ programming languages.
| Language | Code | Unit |
|---|---|---|
| JavaScript | Date.now() | ms |
| TypeScript | Date.now() | ms |
| Java | System.currentTimeMillis() | ms |
| Kotlin | System.currentTimeMillis() | ms |
| Python | int(time.time() * 1000) | ms (from s) |
| C# | DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() | ms |
| Go | time.Now().UnixMilli() | ms |
| Rust | SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() | ms |
| PHP | round(microtime(true) * 1000) | ms (from s) |
| Ruby | Time.now.to_i * 1000 | ms (from s) |
| Swift | Int(Date().timeIntervalSince1970 * 1000) | ms |
| Objective-C | [[NSDate date] timeIntervalSince1970] * 1000 | ms |
| C (POSIX) | clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec*1000 + ts.tv_nsec/1e6 | ms |
| C++ | chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count() | ms |
| Scala | System.currentTimeMillis() | ms |
| Groovy | System.currentTimeMillis() | ms |
| Perl | int(time() * 1000) | ms (approx) |
| Lua | os.time() * 1000 | ms (approx) |
| R | as.numeric(Sys.time()) * 1000 | ms |
| MATLAB | posixtime(datetime('now','TimeZone','UTC')) * 1000 | ms |
| Bash / Shell | date +%s%3N | ms |
| PowerShell | [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() | ms |
| SQL (PostgreSQL) | EXTRACT(EPOCH FROM NOW()) * 1000 | ms |
| SQL (MySQL) | UNIX_TIMESTAMP(NOW(3)) * 1000 | ms |
| SQL (SQLite) | strftime('%s','now') * 1000 | ms |
| Dart / Flutter | DateTime.now().millisecondsSinceEpoch | ms |
| Haskell | round . (* 1000) <$> getPOSIXTime | ms |
| Elixir | System.system_time(:millisecond) | ms |
| Erlang | erlang:system_time(millisecond) | ms |
| Clojure | (System/currentTimeMillis) | ms |
| F# | DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() | ms |
| Julia | round(Int, time() * 1000) | ms |
| Nim | getTime().toUnix() * 1000 | ms |
| Crystal | Time.utc.to_unix_ms | ms |
| Zig | std.time.milliTimestamp() | ms |
Detailed examples for top languages
import time
from datetime import datetime, timezone
# Milliseconds since epoch
ms = int(time.time() * 1000)
print(ms) # e.g. 1773835800123
# Convert ms back to UTC datetime
dt = datetime.fromtimestamp(ms / 1000, tz=timezone.utc)
print(dt.isoformat()) # "2026-03-16T10:30:00.123000+00:00"
package main
import (
"fmt"
"time"
)
func main() {
// Milliseconds (Go 1.17+)
ms := time.Now().UnixMilli()
fmt.Println(ms)
// Convert back to time.Time
t := time.UnixMilli(ms)
fmt.Println(t.UTC().Format(time.RFC3339Nano))
}
using System;
// Milliseconds since epoch
long ms = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
Console.WriteLine(ms);
// Convert back to DateTimeOffset
var dt = DateTimeOffset.FromUnixTimeMilliseconds(ms);
Console.WriteLine(dt.ToString("o")); // ISO 8601
use std::time::{SystemTime, UNIX_EPOCH};
fn main() {
let ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis();
println!("{}", ms);
}