Understanding MySQL Server Time Zone Support

2024/10/22

MySQL has two column types for storing date and time: DATETIME and TIMESTAMP. They look similar on the surface but behave very differently when it comes to timezone handling.

When the Datetime String HAS Timezone Information

has-timezone! Take this example: 2024-10-22 22:47 -03:00 (Oct 22, 2024 10:47 PM UTC-3)

DATETIME (Write)

  1. TZ is given
  2. Converted to UTC → 2024-10-23 01:47 +00:00
  3. Converted to system TZ (e.g. PT = UTC-7) → 2024-10-22 18:47 -07:00
  4. Written to disk in system TZ → 2024-10-22 18:47

DATETIME (Read)

DATETIME (Verification — change system time to UTC, re-read)


TIMESTAMP (Write)

  1. TZ is given
  2. Converted to UTC → 2024-10-23 01:47 +00:00
  3. Written to disk in UTC → 2024-10-23 01:47

TIMESTAMP (Read)

TIMESTAMP (Verification — change system time to UTC, re-read)


When the Datetime String has NO Timezone Information

has-timezone!

Take this example: 2024-10-22 22:47 (no TZ specified)

DATETIME (Write)

  1. No TZ given — assumes system TZ
  2. Converted to UTC → 2024-10-23 05:47 +00:00
  3. Converted back to system TZ → 2024-10-22 22:47 -07:00
  4. Steps 2 & 3 cancel out — written to disk as-is → 2024-10-22 22:47

DATETIME (Read)

DATETIME (Verification — change system time to UTC, re-read)


TIMESTAMP (Write)

  1. No TZ given — assumes system TZ
  2. Converted to UTC → 2024-10-23 05:47 +00:00
  3. Written to disk in UTC → 2024-10-23 05:47

TIMESTAMP (Read)

TIMESTAMP (Verification — change system time to UTC, re-read)


Summary

DATETIME TIMESTAMP
Stored as System TZ (as-is) UTC always
Read as As stored Converted to system TZ
TZ-aware on read ❌ Client must track it ✅ Automatic
Changes with system TZ ❌ No ✅ Yes

The key takeaway: if you need your timestamps to be timezone-aware and portable across systems, use TIMESTAMP. If you need to store a fixed wall-clock time regardless of where the server is, use DATETIME.