Featured image of post Why Timestamp in MySQL Handles Time Zones Automatically

Why Timestamp in MySQL Handles Time Zones Automatically

How Timestamp Simplifies Time Zone Handling

I’ve long been curious why MySQL’s timestamp type can effortlessly handle time zone issues. In practical use with Laravel frameworks, Migration files default to timestamp fields without requiring special attention.


Getting Started

  • Check current database time zone settings
mysql> show variables like "%time_zone%";
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | +08:00 |
+------------------+--------+
2 rows in set (0.30 sec)
  • View table structure
mysql> desc timestamp_test;
+--------------+-----------+------+-----+---------+----------------+
| Field        | Type      | Null | Key | Default | Extra          |
+--------------+-----------+------+-----+---------+----------------+
| id           | int       | NO   | PRI | NULL    | auto_increment |
| created_time | datetime  | YES  |     | NULL    |                |
| created_at   | timestamp | YES  |     | NULL    |                |
+--------------+-----------+------+-----+---------+----------------+
3 rows in set (0.26 sec)
  • Insert data
mysql> insert into timestamp_test(created_time, created_at) values('2020-12-09 08:00:00', '2020-12-09 08:00:00');
Query OK, 1 row affected (0.22 sec)

mysql> select * from timestamp_test;
+----+---------------------+---------------------+
| id | created_time        | created_at          |
+----+---------------------+---------------------+
|  1 | 2020-12-09 08:00:00 | 2020-12-09 08:00:00 |
+----+---------------------+---------------------+
1 row in set (0.06 sec)
  • Test time zone changes
    Now let’s modify the time zone and insert data again:
mysql> SET time_zone = "+00:00";
Query OK, 0 rows affected (0.03 sec)

mysql> insert into timestamp_test(created_time, created_at) values('2020-12-09 08:00:00', '2020-12-09 08:00:00');
Query OK, 1 row affected (0.03 sec)

mysql> SET time_zone = "+08:00";
Query OK, 0 rows affected (0.04 sec)
  • Observe the results
    Both inserts used the same SQL, but the created_at values differ by exactly the time zone offset:
mysql> select * from timestamp_test;
+----+---------------------+---------------------+
| id | created_time        | created_at          |
+----+---------------------+---------------------+
|  1 | 2020-12-09 08:00:00 | 2020-12-09 08:00:00 |
|  2 | 2020-12-09 08:00:00 | 2020-12-09 16:00:00 |
+----+---------------------+---------------------+
2 rows in set (0.06 sec)
  • Verify underlying timestamps
    The stored UNIX timestamps remain constant despite time zone changes:
mysql> select *, unix_timestamp(created_at) from timestamp_test;
+----+---------------------+---------------------+----------------------------+
| id | created_time        | created_at          | unix_timestamp(created_at) |
+----+---------------------+---------------------+----------------------------+
|  1 | 2020-12-09 08:00:00 | 2020-12-09 08:00:00 |                 1607472000 |
|  2 | 2020-12-09 08:00:00 | 2020-12-09 16:00:00 |                 1607500800 |
+----+---------------------+---------------------+----------------------------+
2 rows in set (0.06 sec)

mysql> SET time_zone = "+00:00";
Query OK, 0 rows affected (0.09 sec)

mysql> select *, unix_timestamp(created_at) from timestamp_test;
+----+---------------------+---------------------+----------------------------+
| id | created_time        | created_at          | unix_timestamp(created_at) |
+----+---------------------+---------------------+----------------------------+
|  1 | 2020-12-09 08:00:00 | 2020-12-09 00:00:00 |                 1607472000 |
|  2 | 2020-12-09 08:00:00 | 2020-12-09 08:00:00 |                 1607500800 |
+----+---------------------+---------------------+----------------------------+
2 rows in set (0.18 sec)

The key mechanism: MySQL stores UTC timestamps internally. During writes, it converts local time to UTC using the session time zone. During reads, it converts UTC back to the session’s local time zone. All conversions happen transparently.

  • Practical example:
    • A record stored as 2020-12-09 08:00:00 in +08:00 time zone
    • When queried in +08:00: remains 2020-12-09 08:00:00
    • When queried in +00:00: automatically becomes 2020-12-09 00:00:00

This automatic conversion eliminates manual time zone calculations in applications.