Tutorial

So konvertieren Sie Zeitstempel in SQL

Einführung

Die Arbeit mit Zeitstempeln in SQL-Datenbanken ist eine grundlegende Fähigkeit für Entwickler und Datenbankadministratoren. Dieser Leitfaden behandelt Konvertierungsfunktionen auf den wichtigsten Datenbankplattformen, Leistungsüberlegungen und häufige Fallstricke.

Kurzreferenz

Konvertierungsfunktionen nach Datenbank

MySQL

-- Convert Unix timestamp to DATETIME
SELECT 
  id,
  UNIX_TIMESTAMP(created_at) AS converted_date
FROM events;

-- Convert DATETIME to Unix timestamp
SELECT 
  id,
  UNIX_TIMESTAMP(created_at) AS timestamp_value
FROM events;

-- Current timestamp in Unix format
SELECT UNIX_TIMESTAMP(NOW()) AS current_unix;

Wichtig: MySQL TIMESTAMP hat ein 2038-Problem (Bereich: 1970-01-01 00:00:00 bis 2038-01-19 03:14:07). Verwenden Sie DATETIME oder BIGINT für Datumsangaben außerhalb dieses Bereichs.

PostgreSQL

-- Convert Unix timestamp to TIMESTAMP WITH TIME ZONE
SELECT 
  id,
  to_timestamp(event_timestamp) AS converted_date
FROM events;

-- Convert timestamp to TIMESTAMPTZ with timezone
SELECT 
  id,
  event_timestamp AT TIME ZONE 'America/New_York' AS eastern_time
FROM events;

-- Current timestamp in Unix format
SELECT EXTRACT(EPOCH FROM NOW()) AS current_unix;

Tipp: PostgreSQL TIMESTAMP WITH TIME ZONE berücksichtigt die Zeitzone. Verwenden Sie AT TIME ZONE für Konvertierungen mit Zeitzonenunterstützung.

SQL Server (T-SQL)

-- Convert Unix timestamp to DATETIME2 (higher precision)
SELECT 
  id,
  DATEADD(s, 1970-01-01 00:00:00, UNIX_TIMESTAMP(timestamp_column)) AS converted_date
FROM events;

-- Convert DATETIME2 to Unix timestamp
SELECT 
  id,
  DATEDIFF(s, 1970-01-01 00:00:00, GETDATE()) AS unix_seconds
FROM events;

-- Current timestamp in Unix format
SELECT DATEDIFF(s, 1970-01-01 00:00:00, GETUTCDATE()) AS current_unix;

Hinweis: DATETIME2 stellt Sekundenbruchteile (3 Dezimalstellen) für höhere Präzision bereit. Verwenden Sie die Kombination DATEDIFF/DATEADD für genaue Berechnungen.

SQLite

-- Convert Unix timestamp to DATETIME
SELECT 
  id,
  datetime(timestamp_column, 'unixepoch') AS converted_date
FROM events;

-- Current timestamp in Unix format
SELECT strftime('%s', 'now') AS current_unix;

Hinweis: SQLite verwendet standardmäßig die Unix-Epoche. Verwenden Sie strftime-Modifikatoren für benutzerdefinierte Formate.

Orakel

-- Convert Unix timestamp to DATE
SELECT 
  id,
  TO_DATE('1970-01-01', 'YYYY-MM-DD') AS converted_date
FROM events;

-- Current timestamp
SELECT TO_CHAR(SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') AS current_timestamp
FROM DUAL;

Wichtig: Das Oracle TO_DATE-Format unterscheidet zwischen Groß- und Kleinschreibung. Verwenden Sie Formatbezeichner immer in Großbuchstaben (JJJJ, MM, TT usw.).

Praxisbeispiele

Beispiel 1: Konvertieren und Anzeigen

-- MySQL: Convert and format in single query
SELECT 
  id,
  event_name,
  DATE_FORMAT(UNIX_TIMESTAMP(created_at), '%Y-%m-%d %H:%i') AS formatted_date,
  UNIX_TIMESTAMP(created_at) AS unix_value
FROM events
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
ORDER BY created_at DESC;

Beispiel 2: Nach Datumsbereich filtern

-- PostgreSQL: Efficient date range filtering with timestamp
SELECT 
  id,
  event_name,
  event_timestamp AT TIME ZONE 'UTC' AS utc_time,
  TO_CHAR(event_timestamp AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI') AS formatted_date
FROM events
WHERE event_timestamp >= EXTRACT(EPOCH FROM (NOW() - INTERVAL '7 days'))
  AND event_timestamp < EXTRACT(EPOCH FROM NOW())
ORDER BY event_timestamp DESC;

Beispiel 3: Stapelkonvertierung mit mehreren Formaten

-- SQL Server: Provide multiple timestamp formats in one query
SELECT 
  id,
  event_name,
  event_timestamp,
  CONVERT(VARCHAR, event_timestamp, 120) AS iso8601,  -- Truncate to 120 chars
  CONVERT(DATETIME2, event_timestamp) AS datetime2,
  CONVERT(DATETIME, event_timestamp) AS readable_date,
  YEAR(event_timestamp) AS year,
  MONTH(event_timestamp) AS month,
  DAY(event_timestamp) AS day
FROM events
WHERE event_timestamp IS NOT NULL;

Beispiel 4: Zeitdifferenzberechnung

-- MySQL: Calculate time difference in seconds
SELECT 
  id1, id2,
  timestamp1, timestamp2,
  TIMESTAMPDIFF(SECOND, timestamp2, timestamp1) AS diff_seconds,
  TIMESTAMPDIFF(DAY, timestamp2, timestamp1) AS diff_days,
  SEC_TO_TIME(TIMESTAMPDIFF(SECOND, timestamp2, timestamp1)) AS time_diff
FROM events
WHERE id IN (1, 2);

Leistungsoptimierung

Indexstrategien

Primärindex für Zeitstempelspalte

Best Practice: Erstellen Sie für Bereichsabfragen und Sortiervorgänge immer einen Primärindex für Zeitstempelspalten.

-- MySQL: Primary index for range queries
CREATE TABLE events (
  id INT PRIMARY KEY,
  event_name VARCHAR(255),
  event_timestamp TIMESTAMP,
  INDEX idx_timestamp (event_timestamp)
);

-- PostgreSQL: Partial index for range queries
CREATE TABLE events (
  id BIGSERIAL PRIMARY KEY,
  event_name VARCHAR(255),
  event_timestamp TIMESTAMPTZ,
  INDEX idx_timestamp_range (event_timestamp)
);

-- SQL Server: Include timestamp in covering index
CREATE NONCLUSTERED INDEX idx_event_timestamp
ON events (event_timestamp DESC);

Funktionsindizes

Best Practice: Erstellen Sie funktionale Indizes für berechnete Spalten (Jahr, Monat, Tag) für Datumsgruppierungsabfragen.

-- MySQL: Functional index for date-based grouping
CREATE TABLE events (
  id INT PRIMARY KEY,
  event_name VARCHAR(255),
  event_timestamp TIMESTAMP,
  INDEX idx_year (YEAR(event_timestamp)),
  INDEX idx_month (MONTH(event_timestamp)),
  INDEX idx_day (DAY(event_timestamp))
);

-- PostgreSQL: Generated column for automatic year/month/day
CREATE TABLE events (
  id BIGSERIAL PRIMARY KEY,
  event_name VARCHAR(255),
  event_timestamp TIMESTAMPTZ,
  event_year INTEGER GENERATED ALWAYS AS (EXTRACT(YEAR FROM event_timestamp)) STORED,
  event_month INTEGER GENERATED ALWAYS AS (EXTRACT(MONTH FROM event_timestamp)) STORED
);

Abfrageoptimierung

Vermeiden Sie Funktionsaufrufe für Spalten

Häufiger Fehler: Die Verwendung von Funktionen wie YEAR(), MONTH(), DAY() für indizierte Spalten verhindert die Indexverwendung.

-- BAD: Function call prevents index usage
SELECT id, event_name
FROM events
WHERE YEAR(event_timestamp) = 2024
AND MONTH(event_timestamp) = 6;

-- GOOD: Compare literal values to use index
SELECT id, event_name
FROM events
WHERE event_timestamp >= '2024-01-01 00:00:00'
  AND event_timestamp < '2024-07-01 00:00:00';

Verwenden Sie SARGABLE-fähige Parameter

MySQL-Tipp: Ab MySQL 8.0.18 ermöglicht die Verwendung von SARGABLE-Parametern in vorbereiteten Anweisungen die Indexverwendung.

-- MySQL: Create prepared statement for parameterized queries
PREPARE stmt FROM 'SELECT * FROM events WHERE event_timestamp >= ? AND event_timestamp < ?';

-- Execute with parameters (efficient)
EXECUTE stmt USING @start_ts, @end_ts;

Ergebnismengen begrenzen

Best Practice: Verwenden Sie bei Bereichsabfragen immer LIMIT, um nur die erforderlichen Daten zurückzugeben.

-- MySQL: Paginate large datasets
SELECT id, event_name, event_timestamp
FROM events
WHERE event_timestamp >= UNIX_TIMESTAMP('2025-01-01')
ORDER BY event_timestamp ASC
LIMIT 1000;

-- PostgreSQL: Use cursor-based pagination for large result sets
DECLARE cursor CURSOR FOR
  SELECT id, event_name, event_timestamp
  FROM events
  WHERE event_timestamp >= '2025-01-01 00:00:00 UTC'
  ORDER BY event_timestamp ASC;

Häufige Fallstricke

Zeitzonenbehandlung

MySQL-Zeitzonenfunktionen

Wichtig: MySQL TIMESTAMP speichert KEINE Zeitzoneninformationen. Verwenden Sie TIMESTAMP WITH TIME ZONE für die zeitzonenbezogene Speicherung oder verwenden Sie DATETIME mit separater Zeitzonenspalte.

-- Convert to specific timezone
SELECT 
  id,
  event_name,
  event_timestamp AT TIME ZONE 'America/Los_Angeles' AS la_time,
  event_timestamp AT TIME ZONE 'America/New_York' AS ny_time
FROM events;

-- Get current time in specific timezone
SELECT NOW() AS la_current, CONVERT_TZ(UTC, 'America/New_York') AS ny_current;

Alternative: Speichern Sie den UTC-Zeitstempel und eine separate Zeitzonenspalte für Anwendungen mit mehreren Zeitzonen.

Datenintegrität

Stellen Sie die Konsistenz der Zeitstempel sicher

-- MySQL: Add CHECK constraint for reasonable timestamp range
CREATE TABLE events (
  id INT PRIMARY KEY,
  event_timestamp TIMESTAMP NOT NULL,
  CHECK (event_timestamp BETWEEN 
    UNIX_TIMESTAMP('1970-01-01') AND 
    UNIX_TIMESTAMP('2038-01-19')
  )
);

-- PostgreSQL: Use EXCLUDE constraint to prevent invalid data
CREATE TABLE events (
  id BIGSERIAL PRIMARY KEY,
  event_timestamp TIMESTAMPTZ NOT NULL,
  EXCLUDE ( 
    event_timestamp < EXTRACT(EPOCH FROM TIMESTAMP '1970-01-01') 
    OR event_timestamp > EXTRACT(EPOCH FROM TIMESTAMP '2038-01-19')
  )
);

Migrationsstrategien

Inkrementelle Migration

Strategie: Führen Sie bei großen Tabellen eine Stapelmigration mit zeitstempelbasierten WHERE-Klauseln durch, um lang laufende Transaktionen zu vermeiden.

-- Process 1000 rows at a time, ordered by timestamp
UPDATE events
SET last_processed = 1
WHERE event_timestamp < (
  SELECT event_timestamp
  FROM events
  WHERE last_processed = 0
  ORDER BY event_timestamp ASC
  LIMIT 1000
);

-- Continue until all rows processed
-- Repeat until all events marked as processed

Erweiterte Muster

Umgang mit Epochenzeitstempeln

Datenbankspezifische Muster

MySQL-Muster

Unix-Zeitstempel mit Mikrosekundengenauigkeit

-- MySQL: Using BIGINT for millisecond timestamps
CREATE TABLE high_precision_events (
  id BIGINT PRIMARY KEY,
  event_timestamp BIGINT,  -- Milliseconds since epoch
  event_micros INT(3),  -- Microseconds (0-999)
  INDEX idx_timestamp (event_timestamp DESC)
);

-- Convert millisecond timestamp to human-readable format
SELECT 
  id,
  FROM_UNIXTIME(event_timestamp / 1000) AS seconds,
  DATE_FORMAT(FROM_UNIXTIME(event_timestamp / 1000), '%Y-%m-%d %H:%i:%s') AS formatted
FROM high_precision_events;

PostgreSQL-Muster

Verwenden von EXTRACT für Datumskomponenten

-- PostgreSQL: Extract date components for filtering
SELECT 
  id,
  event_name,
  EXTRACT(YEAR FROM event_timestamp) AS year,
  EXTRACT(MONTH FROM event_timestamp) AS month,
  EXTRACT(DAY FROM event_timestamp) AS day,
  DATE_TRUNC('day', event_timestamp) AS date_only
FROM events
WHERE event_name = 'Daily Backup';

Best Practices-Zusammenfassung

Leistungscheckliste

✅ Use appropriate data types (TIMESTAMP vs DATETIME)
✅ Create indexes on timestamp columns
✅ Use SARGABLE-able parameters when possible
✅ Limit result sets with pagination
✅ Avoid function calls on indexed columns
✅ Use WHERE clauses on timestamp for range queries
✅ Consider generated columns for date filtering
✅ Validate timestamp ranges on input
✅ Handle timezones explicitly (don't rely on implicit conversion)
✅ Use CHECK/EXCLUDE constraints for data integrity
❌ Don't store both timestamp and datetime for same data
❌ Don't use VARCHAR for timestamp columns
❌ Don't convert timestamp to string for every query

Bei Zeitstempelanwendungen mit hohem Volumen (>1 Mio. Zeilen) können geeignete Indizierungs- und Abfragemuster die Abfragezeit um 50–80 % reduzieren.

Verwandte Tools