Guides

Temps Epoch Expliqué

Cette page est provisoirement disponible en anglais. La traduction française est en préparation.

Introduction

Epoch time (also called Unix timestamp or POSIX time) is a system for describing a point in time as the number of seconds that have elapsed since a specific reference date and time. Understanding epoch time is fundamental for developers, system administrators, and anyone working with timestamps in computing.

What is Epoch Time

Definition

Epoch time represents time as a continuous count of time units (usually seconds) from a fixed reference point called the "epoch":

Epoch Timestamp = Current Time - Epoch Start Time

Example (Unix Epoch):
  Epoch Start: January 1, 1970, 00:00:00 UTC
  Current Time: January 8, 2024, 00:00:00 UTC
  Timestamp: 1704672000 seconds since epoch

Unix Epoch (POSIX Time)

The most widely used epoch system is Unix epoch (POSIX time):

Unix Epoch Reference:
  Start Date: January 1, 1970, 00:00:00 UTC
  Time Units: Seconds (some systems use milliseconds)
  Notation: 32-bit signed integer (common) or 64-bit
  Max Range (32-bit): 1901-12-13 to 2038-01-19
  Current Use: Linux, Unix, macOS, most programming languages

Interesting Fact: Unix epoch was chosen because it was a round number at the time Unix was being developed, making calculations simple and avoiding negative timestamps for most practical uses.

History of Unix Epoch

Unix epoch was established in the early 1970s:

  • 1970: Unix epoch date chosen (January 1, 1970)
  • 1971-1973: Initial Unix systems used time_t type (32-bit)
  • 1988: POSIX standard formally adopted Unix time
  • 2000s: Most systems transitioned to 64-bit time_t to avoid year 2038 problem
  • 2020s: Modern systems use 64-bit epoch timestamps

Why 1970? It was approximately the time Unix was being developed and represents a convenient "zero point" before most computer systems existed, avoiding negative timestamps for early computing history.

Different Epoch Systems

Common Epoch References

1. Unix Epoch (POSIX)
   Start: January 1, 1970, 00:00:00 UTC
   Units: Seconds (or milliseconds)
   Usage: Unix, Linux, macOS, most programming languages

2. Windows FILETIME
   Start: January 1, 1601, 00:00:00 UTC
   Units: 100-nanosecond intervals
   Usage: Windows file systems, NTFS

3. Mac HFS/HFS+ Epoch
   Start: January 1, 1904, 00:00:00 UTC
   Units: Seconds
   Usage: Classic Mac OS (pre-OS X)

4. GPS Epoch
   Start: January 6, 1980, 00:00:00 UTC
   Units: Seconds
   Usage: GPS systems, navigation

5. NTP Timestamp
   Start: January 1, 1900, 00:00:00 UTC
   Units: Seconds (64-bit)
   Usage: Network Time Protocol

6. WebKit/Chrome Epoch
   Start: January 1, 1601, 00:00:00 UTC
   Units: Microseconds
   Usage: Web browsers (Date object)

Important: Always verify which epoch system your system or API uses before converting timestamps.

JavaScript Epoch

JavaScript uses Unix epoch in milliseconds:

// JavaScript Date uses Unix epoch in milliseconds
const now = Date.now();
console.log(now);  // e.g., 1704672000000 (milliseconds)

// Convert to seconds
const nowSec = Math.floor(Date.now() / 1000);
console.log(nowSec);  // e.g., 1704672000 (seconds)

// Create from Unix epoch seconds
const date = new Date(1704672000 * 1000);
console.log(date.toISOString());  // "2024-01-08T00:00:00.000Z"

Python Epoch

Python's time.time() uses Unix epoch in seconds:

import time
from datetime import datetime

# Get current Unix timestamp (seconds)
now_ts = time.time()
print(now_ts)  # e.g., 1704672000.123

# Create datetime from Unix timestamp
dt = datetime.fromtimestamp(1704672000)
print(dt)  # 2024-01-08 00:00:00

# Get UTC timestamp
now_utc = datetime.now(timezone.utc).timestamp()
print(now_utc)  # e.g., 1704672000

Java Epoch

Java uses Unix epoch in milliseconds (consistent with JavaScript):

import java.time.Instant;

// Get current timestamp (milliseconds)
long nowMs = System.currentTimeMillis();
System.out.println(nowMs);  // e.g., 1704672000000

// Get from Instant (Java 8+)
Instant now = Instant.now();
long ts = now.getEpochSecond();
System.out.println(ts);  // e.g., 1704672000

// Create Instant from Unix timestamp
Instant instant = Instant.ofEpochSecond(1704672000);
System.out.println(instant);  // 2024-01-08T00:00:00Z

Timestamp Limits and Ranges

32-bit Signed Integer Limits

Traditional Unix timestamps use 32-bit signed integers:

32-bit Signed Integer Range:
  Min Value: -2147483648 (seconds)
  Max Value: 2147483647 (seconds)
  Min Date: December 13, 1901, 20:45:52 UTC
  Max Date: January 19, 2038, 03:14:07 UTC
  Current Date: January 8, 2024
  Time to Overflow: ~14 years

Critical: January 19, 2038, 03:14:07 UTC is known as the "Year 2038 problem" - 32-bit Unix timestamps will overflow and wrap to negative values, breaking many systems.

64-bit Timestamps

Modern systems use 64-bit timestamps to solve overflow issues:

64-bit Signed Integer Range:
  Min Value: -9223372036854775808 (seconds)
  Max Value: 9223372036854775807 (seconds)
  Min Date: ~293 billion years BCE
  Max Date: ~293 billion years CE
  Practical Limit: Effectively infinite for all practical purposes
  Current Date: January 8, 2024

Best Practice: Always use 64-bit timestamps in new systems to avoid year 2038 problem and other overflow issues.

Millisecond vs Second Precision

Different systems use different precision:

Second Precision (Traditional Unix):
  Units: Seconds since epoch
  Range (32-bit): 136 years
  Use: Unix/Linux systems, APIs, databases
  Example: 1704672000

Millisecond Precision (Modern Systems):
  Units: Milliseconds since epoch
  Range (32-bit): ~49 days (not practical)
  Range (64-bit): ~293 million years
  Use: JavaScript, Java, most modern APIs
  Example: 1704672000000

Conversion Formula:

> Seconds to Milliseconds: seconds * 1000
> Milliseconds to Seconds: milliseconds / 1000
>

The Year 2038 Problem

What is the Year 2038 Problem?

The Year 2038 problem is a time computing bug where 32-bit signed Unix timestamps will overflow on January 19, 2038, at 03:14:07 UTC.

Overflow Timestamp: 2147483647
Date: January 19, 2038, 03:14:07 UTC

After Overflow (Signed 32-bit wraps to negative):
Next Second: -2147483648
Date: December 13, 1901, 20:45:52 UTC

Critical Impact: Systems using 32-bit timestamps will fail or produce incorrect dates after 2038-01-19.

Affected Systems

Systems potentially affected by year 2038 problem:

  • Legacy Unix systems still using 32-bit time_t
  • Embedded systems with limited memory
  • Older database systems
  • File systems using 32-bit timestamps
  • Network protocols with 32-bit time fields
  • Some APIs still using 32-bit integers

Solutions

Solution 1: Upgrade to 64-bit
  - Use time64_t or equivalent
  - Increases range to ~293 billion years
  - Required for long-term systems

Solution 2: Offset Timestamps
  - Store timestamps with epoch offset
  - Example: Store "years since 2000" instead of seconds since 1970
  - Requires conversion on read/write

Solution 3: Use Alternative Formats
  - Use ISO 8601 strings (no overflow)
  - Use datetime types with larger range
  - Store year, month, day separately

Prevention: When designing new systems, always use 64-bit timestamps or datetime objects with larger ranges.

Converting Between Epochs

Unix to Windows FILETIME

function unixToWindowsFiletime(unixTimestamp) {
  // Unix to FILETIME: 100-nanosecond intervals since 1601-01-01
  const WINDOWS_EPOCH = 0x019DB1DED53E8000; // FILETIME of Unix epoch
  const NANOSECONDS_PER_MILLISECOND = 10000;

  const filetime = (unixTimestamp * 1000 + 11644473600000) * NANOSECONDS_PER_MILLISECOND;

  // For large numbers, use BigInt
  return BigInt(unixTimestamp) * 10000n + 116444736000000000n;
}

// Example
const filetime = unixToWindowsFiletime(1704672000);
console.log(filetime);  // 1336477752000000000

Windows FILETIME to Unix

function windowsFiletimeToUnix(filetime) {
  const NANOSECONDS_PER_MILLISECOND = 10000;

  // FILETIME to Unix: subtract Windows epoch
  const unixMs = (filetime - 116444736000000000) / 10000n;

  return Number(unixMs / 1000n);
}

// Example
const filetime = 133647752000000000n;
const unixTs = windowsFiletimeToUnix(filetime);
console.log(unixTs);  // 1704672000

Unix to GPS Time

import datetime

def unix_to_gps(unix_timestamp):
    """Convert Unix timestamp to GPS timestamp"""
    # GPS epoch: January 6, 1980
    # Unix epoch: January 1, 1970
    # Difference: 315964800 seconds
    GPS_EPOCH_OFFSET = 315964800

    return unix_timestamp - GPS_EPOCH_OFFSET

def gps_to_unix(gps_timestamp):
    """Convert GPS timestamp to Unix timestamp"""
    GPS_EPOCH_OFFSET = 315964800
    return gps_timestamp + GPS_EPOCH_OFFSET

# Example
unix_ts = 1704672000
gps_ts = unix_to_gps(unix_ts)
print(f"GPS Timestamp: {gps_ts}")  # 5355687200

Unix to Mac HFS Time

import datetime

def unix_to_mac_hfs(unix_timestamp):
    """Convert Unix timestamp to Mac HFS timestamp"""
    # Mac HFS epoch: January 1, 1904
    # Unix epoch: January 1, 1970
    # Difference: -2082844800 seconds (Mac is earlier)
    MAC_EPOCH_OFFSET = -2082844800

    return unix_timestamp - MAC_EPOCH_OFFSET

def mac_hfs_to_unix(mac_timestamp):
    """Convert Mac HFS timestamp to Unix timestamp"""
    MAC_EPOCH_OFFSET = -2082844800
    return mac_timestamp + MAC_EPOCH_OFFSET

# Example
unix_ts = 1704672000
mac_ts = unix_to_mac_hfs(unix_ts)
print(f"Mac HFS Timestamp: {mac_ts}")  # 3787516800

Practical Applications

Calculating Duration

import time

def calculate_duration(start_ts, end_ts):
    """Calculate duration between two Unix timestamps"""
    duration_seconds = end_ts - start_ts

    hours = duration_seconds // 3600
    minutes = (duration_seconds % 3600) // 60
    seconds = duration_seconds % 60

    return f"{hours}h {minutes}m {seconds}s"

# Example
start = 1704587200  # 2024-01-07 00:00:00
end = 1704673600    # 2024-01-08 00:00:00
print(calculate_duration(start, end))  # "24h 0m 0s"

Future/Past Time Calculation

function timeUntil(targetTimestamp) {
  const now = Date.now() / 1000;
  const diff = targetTimestamp - now;

  if (diff <= 0) {
    return { type: 'past', text: 'Already passed' };
  }

  const days = Math.floor(diff / 86400);
  const hours = Math.floor((diff % 86400) / 3600);
  const minutes = Math.floor((diff % 3600) / 60);

  return {
    type: 'future',
    text: `${days} days, ${hours} hours, ${minutes} minutes`
  };
}

// Calculate time until end of 2037
const target = 2155999999; // December 31, 2037
console.log(timeUntil(target));
// "511 days, 2 hours, 33 minutes"

Date Range Validation

import time

def is_valid_unix_timestamp(ts, allow_future=True):
    """Validate Unix timestamp is within reasonable range"""
    # Minimum: January 1, 1970
    MIN_TIMESTAMP = 0

    # Maximum: January 19, 2038 (32-bit limit)
    MAX_TIMESTAMP = 2147483647

    if ts < MIN_TIMESTAMP:
        return False, "Timestamp is before Unix epoch"

    if not allow_future and ts > time.time():
        return False, "Timestamp is in the future"

    if ts > MAX_TIMESTAMP:
        return False, "Timestamp exceeds 32-bit limit"

    return True, "Valid"

# Example
print(is_valid_unix_timestamp(1704672000))  # (True, "Valid")
print(is_valid_unix_timestamp(-1000))  # (False, "Timestamp is before Unix epoch")
print(is_valid_unix_timestamp(3000000000))  # (False, "Timestamp exceeds 32-bit limit")

Batch Conversion

function convertUnixTimestamps(timestamps) {
  return timestamps.map(ts => {
    const date = new Date(ts * 1000);
    return {
      timestamp: ts,
      isoString: date.toISOString(),
      utcString: date.toUTCString(),
      localString: date.toLocaleString()
    };
  });
}

// Example batch conversion
const timestamps = [1704587200, 1704673600, 1704760000];
const results = convertUnixTimestamps(timestamps);
console.log(results);
/*
[
  {
    timestamp: 1704587200,
    isoString: "2024-01-07T00:00:00.000Z",
    utcString: "Sun, 07 Jan 2024 00:00:00 GMT",
    localString: "1/7/2024, 12:00:00 AM"
  },
  ...
]
*/

Best Practices

Timestamp Selection Guidelines

When choosing timestamp precision:
  ✅ Use seconds for Unix/Linux compatibility
  ✅ Use milliseconds for JavaScript/Java/Web compatibility
  ✅ Use 64-bit integers for future-proof systems
  ✅ Use ISO 8601 strings for cross-system compatibility
  ✅ Document epoch system in API specifications
  ❌ Don't mix precision levels in same API
  ❌ Don't use 32-bit timestamps for long-term systems
  ❌ Don't assume all systems use Unix epoch

Storage Recommendations

Database storage:
  ✅ Store as TIMESTAMP or DATETIME (64-bit)
  ✅ Store timezone information separately
  ✅ Use UTC for all storage
  ✅ Validate timestamp ranges on input
  ❌ Don't store as VARCHAR or STRING
  ❌ Don't store local times without timezone metadata
  ❌ Don't use 32-bit integers for new systems

API Design

REST API design:
  ✅ Use ISO 8601 in JSON responses (e.g., "2024-01-08T00:00:00Z")
  ✅ Include timezone information (Z or offset)
  ✅ Document timestamp precision (seconds or milliseconds)
  ✅ Support both input formats for flexibility
  ✅ Return descriptive errors for invalid timestamps
  ❌ Don't use locale-specific formats in APIs
  ❌ Don't assume client timezone
  ❌ Don't silently correct invalid timestamps

Testing Strategies

import datetime

def test_epoch_conversions():
    """Test epoch conversion edge cases"""
    test_cases = [
        ("Unix epoch start", 0, datetime.datetime(1970, 1, 1)),
        ("Current time", 1704672000, datetime.datetime(2024, 1, 8)),
        ("Year 2038 limit", 2147483647, datetime.datetime(2038, 1, 19, 3, 14, 7)),
        ("Negative timestamp", -86400, datetime.datetime(1969, 12, 31, 0, 0, 0)),
    ]

    for name, timestamp, expected in test_cases:
        result = datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc)
        assert result == expected, f"Failed: {name}"

    print("All epoch conversion tests passed!")

test_epoch_conversions()

Related Tools

Additional Resources

For most applications, Unix epoch (January 1, 1970) is the de facto standard. However, always verify the epoch system when integrating with external systems, APIs, or legacy data, as different systems may use different reference dates.

Quick Reference

Common Epoch Timestamps:
  0: January 1, 1970, 00:00:00 UTC (Unix epoch start)
  946684800: January 1, 2000, 00:00:00 UTC
  1577836800: January 1, 2020, 00:00:00 UTC
  1704067200: January 1, 2024, 00:00:00 UTC
  2147483647: January 19, 2038, 03:14:07 UTC (32-bit max)
  253402300799: December 31, 9999, 23:59:59 UTC (Common limit)