Guide

Epochenzeit erklärt

Einführung

Die Epochenzeit (auch Unix-Zeitstempel oder POSIX-Zeit genannt) ist ein System zur Beschreibung eines Zeitpunkts als Anzahl der Sekunden, die seit einem bestimmten Referenzdatum und einer bestimmten Referenzzeit vergangen sind. Das Verständnis der Epochenzeit ist für Entwickler, Systemadministratoren und alle, die in der Datenverarbeitung mit Zeitstempeln arbeiten, von grundlegender Bedeutung.

Was ist Epochenzeit?

Definition

Die Epochenzeit stellt die Zeit als kontinuierliche Zählung von Zeiteinheiten (normalerweise Sekunden) ab einem festen Referenzpunkt namens „Epoche“ dar:

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-Epoche (POSIX-Zeit)

Das am weitesten verbreitete Epochensystem ist die Unix-Epoche (POSIX-Zeit):

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

Interessante Tatsache: Die Unix-Epoche wurde ausgewählt, weil sie zum Zeitpunkt der Unix-Entwicklung eine runde Zahl war, was Berechnungen vereinfacht und negative Zeitstempel für die meisten praktischen Anwendungen vermeidet.

Geschichte der Unix-Epoche

Die Unix-Epoche wurde in den frühen 1970er Jahren gegründet:

  • 1970: Datum der Unix-Epoche gewählt (1. Januar 1970)
  • 1971-1973: Erste Unix-Systeme verwendeten den Typ time_t (32-Bit)
  • 1988: Der POSIX-Standard übernimmt offiziell die Unix-Zeit
  • 2000er Jahre: Die meisten Systeme wurden auf 64-Bit time_t umgestellt, um das Jahr 2038-Problem zu vermeiden
  • 2020er Jahre: Moderne Systeme verwenden 64-Bit-Epochenzeitstempel

Warum 1970? Es war ungefähr die Zeit, in der Unix entwickelt wurde, und stellt einen praktischen „Nullpunkt“ dar, bevor die meisten Computersysteme existierten, wodurch negative Zeitstempel für die frühe Computergeschichte vermieden wurden.

Verschiedene Epochensysteme

Gemeinsame Epochenreferenzen

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)

Wichtig: Überprüfen Sie immer, welches Epochensystem Ihr System oder Ihre API verwendet, bevor Sie Zeitstempel konvertieren.

JavaScript-Epoche

JavaScript verwendet die Unix-Epoche in Millisekunden:

// 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-Epoche

Pythons time.time() verwendet die Unix-Epoche in Sekunden:

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-Epoche

Java verwendet die Unix-Epoche in Millisekunden (im Einklang mit 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

Zeitstempelgrenzen und -bereiche

32-Bit-Ganzzahlgrenzen mit Vorzeichen

Herkömmliche Unix-Zeitstempel verwenden 32-Bit-Ganzzahlen mit Vorzeichen:

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

Kritisch: 19. Januar 2038, 03:14:07 UTC ist als „Jahr-2038-Problem“ bekannt – 32-Bit-Unix-Zeitstempel laufen über und werden auf negative Werte umgebrochen, wodurch viele Systeme kaputt gehen.

64-Bit-Zeitstempel

Moderne Systeme verwenden 64-Bit-Zeitstempel, um Überlaufprobleme zu lösen:

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: Verwenden Sie in neuen Systemen immer 64-Bit-Zeitstempel, um das Jahr-2038-Problem und andere Überlaufprobleme zu vermeiden.

Millisekunde vs. Sekundenpräzision

Verschiedene Systeme verwenden unterschiedliche Präzision:

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

Umrechnungsformel:

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

Das Jahr-2038-Problem

Was ist das Problem des Jahres 2038?

Das Jahr-2038-Problem ist ein Zeitberechnungsfehler, bei dem 32-Bit-signierte Unix-Zeitstempel am 19. Januar 2038 um 03:14:07 UTC überlaufen.

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

Kritische Auswirkung: Systeme, die 32-Bit-Zeitstempel verwenden, werden nach dem 19.01.2038 ausfallen oder falsche Daten erzeugen.

Betroffene Systeme

Systeme, die möglicherweise vom Problem des Jahres 2038 betroffen sind:

– Ältere Unix-Systeme verwenden immer noch 32-Bit time_t

  • Eingebettete Systeme mit begrenztem Speicher
  • Ältere Datenbanksysteme – Dateisysteme mit 32-Bit-Zeitstempeln
  • Netzwerkprotokolle mit 32-Bit-Zeitfeldern – Einige APIs verwenden immer noch 32-Bit-Ganzzahlen

Lösungen

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

Vorbeugung: Verwenden Sie beim Entwerfen neuer Systeme immer 64-Bit-Zeitstempel oder Datum/Uhrzeit-Objekte mit größeren Bereichen.

Konvertieren zwischen Epochen

Unix zu 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 zu 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 zu GPS-Zeit

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 zu 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

Praktische Anwendungen

Berechnung der Dauer

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"

Berechnung der Zukunft/Vergangenheit

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"

Datumsbereichsvalidierung

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")

Stapelkonvertierung

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

Richtlinien zur Zeitstempelauswahl

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

Speicherempfehlungen

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

Teststrategien

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()

Verwandte Tools

Zusätzliche Ressourcen

Für die meisten Anwendungen ist die Unix-Epoche (1. Januar 1970) der De-facto-Standard. Überprüfen Sie jedoch immer das Epochensystem, wenn Sie externe Systeme, APIs oder Legacy-Daten integrieren, da verschiedene Systeme möglicherweise unterschiedliche Referenzdaten verwenden.

Kurzreferenz

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)