Pull to refresh

Datetime или timestamp

MySQL *
На днях я столкнулся с тем, что многие разработчики не знают в чём отличие типов данных DATETIME и TIMESTAMP в MySQLе, а так же как хранить дату и время, если необходимо учитывать разные часовые пояса для разных пользователей веб-приложения. Поэтому хочу дать ниже разъяснения с пояснениями.

DATETIME
Хранит время в виде целого числа вида YYYYMMDDHHMMSS, используя для этого 8 байтов. Это время не зависит от временной зоны. Оно всегда отображается при выборке точно так же, как было сохранено, независимо от того какой часовой пояс установлен в MySQL. Даю пример:

mysql> create table `dt1` ( col datetime NOT NULL );
mysql> SET @@session.time_zone='+00:00';
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2009-06-04 18:13:56 |
+---------------------+

mysql> insert into dt1 values(now());

mysql> SET @@session.time_zone='+01:00';
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2009-06-04 19:14:20 |
+---------------------+

mysql> insert into dt1 values(now());

mysql> SET @@session.time_zone='+00:00';
mysql> select * from dt1;
+---------------------+
| col |
+---------------------+
| 2009-06-04 18:14:10 |
| 2009-06-04 19:14:27 |
+---------------------+


TIMESTAMP
Хранит 4-байтное целое число, равное количеству секунд, прошедших с полуночи 1 января 1970 года по усреднённому времени Гринвича (т.е. нулевой часовой пояс, точка отсчёта часовых поясов). При получении из базы отображается с учётом часового пояса. Часовой пояс может быть задан в операционной системе, глобальных настройках MySQL или в конкретной сессии. Запомните, что сохраняется всегда количество секунд по UTC (универсальное координированное время, солнечное время на меридиане Гринвича), а не по локальному часовому поясу. Пример:

mysql> create table tm1 (col timestamp not null);
mysql> set @@session.time_zone = '+00:00';
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2009-06-04 18:24:54 |
+---------------------+
mysql> insert into tm1 values(now());
mysql> select * from tm1;
+---------------------+
| col |
+---------------------+
| 2009-06-04 18:25:08 |
+---------------------+

mysql> set @@session.time_zone = '+01:00';
mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2009-06-04 19:25:21 |
+---------------------+
mysql> insert into tm1 values(now());
mysql> select * from tm1;
+---------------------+
| col |
+---------------------+
| 2009-06-04 19:25:08 |
| 2009-06-04 19:25:26 |
+---------------------+

mysql> set @@session.time_zone = '+00:00';
mysql> select * from tm1;
+---------------------+
| col |
+---------------------+
| 2009-06-04 18:25:08 |
| 2009-06-04 18:25:26 |
+---------------------+


Ещё одно отличие! TIMESTAMP по умолчанию NOT NULL, а его значение по умолчанию равно NOW().

mysql> insert into dt1 values(null);
ERROR 1048 (23000): Column 'col' cannot be null
mysql> insert into tm1 values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from tm1;
+---------------------+
| col |
+---------------------+
| 2009-06-04 18:25:08 |
| 2009-06-04 18:25:26 |
| 2009-06-04 18:32:50 |
+---------------------+


Дополнение. Для тех, кого смущает использование функции NOW().

mysql> set @@session.time_zone = '+00:00';
mysql> insert into dt1 values('2009-06-04 22:00:00');
mysql> set @@session.time_zone = '+01:00';
mysql> select * from dt1;
+---------------------+
| col |
+---------------------+
| 2009-06-04 22:00:00 |
+---------------------+

mysql> set @@session.time_zone = '+00:00';
mysql> insert into tm1 values('2009-06-04 22:00:00');
mysql> set @@session.time_zone = '+01:00';
mysql> select * from tm1;
+---------------------+
| col |
+---------------------+
| 2009-06-04 23:00:00 |
+---------------------+
Tags: datetimetimestampчасовой пояс
Hubs: MySQL
Total votes 77: ↑67 and ↓10 +57
Comments 132
Comments Comments 132