Должен ли я использовать в MySQL тип данных datetime или timestamp?

Вы бы порекомендовали использовать поле дата и время или отметка времени, и почему (с использованием MySQL)?

Я работаю с PHP на стороне сервера.

это имеет некоторую релевантную информацию codeproject.com/Tips/1215635/MySQL-DATETIME-vs-TIMESTAMP

Waqleh 26.07.2018 11:46

Если вы хотите, чтобы ваше приложение не работало в феврале 2038 года, используйте временную метку. Проверьте диапазон дат.

Wilson Hauck 11.03.2020 20:55

Если есть хотя бы малейшая вероятность, что вашей базе данных может потребоваться хранить значения в другом часовом поясе или получать соединения от приложения в другом часовом поясе, подумайте об использовании ISO-8601 CHAR для всех ваших важных временных меток. См. Этот вопрос: stackoverflow.com/questions/40670532/…

Alex R 19.09.2020 21:59
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
2 802
3
938 102
39
Перейти к ответу Данный вопрос помечен как решенный

Ответы 39

Я бы всегда использовал временную метку Unix при работе с MySQL и PHP. Основная причина этого в том, что метод Дата по умолчанию в PHP использует метку времени в качестве параметра, поэтому синтаксический анализ не требуется.

Чтобы получить текущую временную метку Unix в PHP, просто выполните time();
а в MySQL сделать SELECT UNIX_TIMESTAMP();.

-1 На самом деле я думаю, что приведенный ниже ответ лучше - использование datetime позволяет вам добавить больше логики для обработки даты в сам MySQL, что может быть очень полезно.

Toby Hede 04.01.2009 08:00

Разве не было тестов, показывающих, что сортировка в MySQL медленнее, чем в php?

sdkfasldf 17.05.2010 17:59

ну, это зависит от обстоятельств, иногда полезно использовать его, когда мы не хотим использовать strtotime. (php5.3 dep)

Adam Ramadhan 02.09.2010 09:59

вы можете вставить логику в mysql, просто используя FROM_UNIXTIME, если необходимо

inarilo 25.05.2017 11:10

Раньше я использовал все временные метки Unix в своих PHP-приложениях и в MySQL, однако я обнаружил, что намного удобнее хранить дату и время в MySQL как собственные типы даты и времени. Это особенно полезно для отчетов и просто для просмотра наборов данных. Со временем, когда я разочаровался в необходимости копировать / пропускать временные метки Unix, я начал переключаться. Я совершенно уверен, что есть производительность и другие плюсы / минусы, но в зависимости от вашего варианта использования удобство может быть более важным, чем небольшие микрооптимизации.

DavidScherer 11.05.2018 21:02

Поле timestamp - это частный случай поля datetime. Вы можете создавать столбцы timestamp, чтобы иметь специальные свойства; он может быть настроен на самообновление при создании и / или обновлении.

В терминах «больших» баз данных timestamp имеет несколько триггеров для особых случаев.

Какой будет правильный, полностью зависит от того, что вы хотите делать.

Нет, разница не просто в «частном случае». Поскольку часовые пояса сеанса, который устанавливает / запрашивает значения, задействованы по-разному.

dolmen 19.01.2016 15:50

Я рад, что вы добавили: «Правильный вариант полностью зависит от того, что вы хотите сделать». На SE слишком много ответов, в которых без достаточных оснований говорится: «Вы должны никогда делать X» или «Вы должны всегда делать Y».

Agi Hammerthief 23.08.2018 11:35
Ответ принят как подходящий

Метки времени в MySQL обычно используются для отслеживания изменений в записях и часто обновляются при каждом изменении записи. Если вы хотите сохранить определенное значение, вы должны использовать поле даты и времени.

Если вы имели в виду, что хотите выбрать между использованием метки времени UNIX или собственного поля даты и времени MySQL, выберите собственный формат. Таким образом вы можете выполнять вычисления в MySQL ("SELECT DATE_ADD(my_datetime, INTERVAL 1 DAY)"), и просто изменить формат значения на временную метку UNIX ("SELECT UNIX_TIMESTAMP(my_datetime)"), когда вы запрашиваете запись, если вы хотите работать с ней с помощью PHP.

Важное отличие состоит в том, что DATETIME представляет дату (как в календаре) и время (как можно наблюдать на настенных часах), а TIMESTAMP представляет четко определенный момент времени. Это может быть очень важно, если ваше приложение обрабатывает часовые пояса. Как давно было "2010-09-01 16:31:00"? Это зависит от того, в каком часовом поясе вы находитесь. Для меня это было всего несколько секунд назад, для вас это может означать время в будущем. Если я скажу 1283351460 секунд с момента '1970-01-01 00:00:00 UTC', вы точно знаете, о каком моменте времени я говорю. (См. Отличный ответ Нира ниже). [Обратная сторона: допустимый диапазон].

MattBianco 01.09.2010 18:36

Еще одно отличие: запросы с «родным» datetime не будут кешироваться, а запросы с timestamp - будут.

OZ_ 28.04.2011 21:37

«Временные метки в MySQL обычно используются для отслеживания изменений в записях» Не думаю, что это хороший ответ. Timestamp намного мощнее и сложнее, чем те, что сказали MattBianco и Nird. Хотя вторая часть ответа очень хороша. То, что сказал Бливет, правда, и это хороший совет.

santiagobasulto 16.05.2011 18:00

Я принимаю это решение на семантической основе.

Я использую временную метку, когда мне нужно записать (более или менее) фиксированный момент времени. Например, когда запись была вставлена ​​в базу данных или когда произошло какое-то действие пользователя.

Я использую поле datetime, когда дату / время можно устанавливать и изменять произвольно. Например, когда пользователь может сохранять встречи с изменениями позже.

timestamp - фиксированная точка времени, универсальное координированное время datetime - относительно точки зрения, относительно привязки ко времени (например, часовой пояс по местному времени), может быть .. Координатное местное время?

yucer 17.12.2013 14:48

Я всегда использую поля DATETIME для чего-либо, кроме метаданных строки (даты создания или изменения).

Как упомянул в документации MySQL:

The DATETIME type is used when you need values that contain both date and time information. MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD HH:MM:SS' format. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.

...

The TIMESTAMP data type has a range of '1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' UTC. It has varying properties, depending on the MySQL version and the SQL mode the server is running in.

Вы, скорее всего, достигнете нижнего предела TIMESTAMP для общего использования - например, сохранение даты рождения.

вы также можете легко достичь предела верхний, если вы работаете в банковском деле или в сфере недвижимости ... 30-летняя ипотека выходит за рамки 2038 года

Kip 10.08.2012 18:47

Конечно, используйте 64-битные временные метки Unix. Например, в Java new Date().getTime() уже дает вам 64-битное значение.

Sergey Orshanskiy 08.10.2013 05:16

Без понятия. Это гораздо более серьезная проблема, чем просто MySQL, и простого решения нет: en.wikipedia.org/wiki/Year_2038_problem Я не верю, что MySQL может просто объявлять временные метки теперь 64-битными и предполагать, что все будет в порядке. Они не контролируют оборудование.

scronide 10.02.2015 21:11

Я предпочитаю использовать временную метку, чтобы хранить все в одном общем необработанном формате и форматировать данные в PHP-коде или в вашем SQL-запросе. Бывают случаи, когда в вашем коде удобно хранить все в считанные секунды.

TIMESTAMP составляет 4 байта против 8 байтов для DATETIME.

http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html

Но, как сказал Скронид, у него есть нижний предел 1970 года. Хотя он отлично подходит для всего, что может случиться в будущем;)

Будущее заканчивается в 2038-01-19 03:14:07 UTC.

MattBianco 01.09.2010 18:39

Это глупо. Я думал, что тип TIMESTAMP будет «готов к будущему», потому что он относительно новый. Вы не можете беспокоиться о преобразовании даты и времени в UTC и обратно каждый раз, когда вы работаете с разными часовыми поясами. Они должны были сделать TIMESTAMP больше .. как минимум на 1 байт. это добавит 68 * 255 = 17340 лет ... хотя он не будет выровнен на 32 бита.

NickSoft 27.03.2012 13:55

Вы знаете, почему TIMESTAMP заканчивается в 2038 году? Потому что это целое число, а у целых чисел есть предел, равный 2147483647. Я думаю, что причина в этом. Может быть, если они изменят его тип на varchar и изменят способ манипулирования им, он будет «готов к будущему».

vinsa 21.01.2015 00:16

@vinsa, я не думаю, что к тому времени это будет готово к будущему. Все еще помните ошибку 2000 года? Наступает 2038 год.

Pacerier 10.02.2015 09:02

К 2038 году MySQL (если он все еще существует) просто обновит поле TIMESTAMP, чтобы использовать более 4 байтов и разрешить более широкий диапазон

the_nuts 27.06.2017 13:21

@the_nuts - на самом деле, план состоит в том, чтобы преобразовать текущее 32-битное целое число подписанный (которое тратит знаковый бит) в 32-битное целое число беззнаковый. Расширение метки времени до 2116 года. Прочтите эту ссылку, если хотите узнать, почему сейчас эффективно используется только 31 бит. (подсказка: совместимость со встроенным методом отметки времени * nix.)

ToolmakerSteve 28.10.2019 16:01

DATETIME теперь составляет 5 байтов с mysql 5.6.4 - dev.mysql.com/doc/internals/en/…

Curtis Yallop 10.01.2020 20:06

В MySQL 5 и выше значения TIMESTAMP преобразуются из текущего часового пояса в UTC для хранения и конвертируются обратно из UTC в текущий часовой пояс для извлечения. (Это происходит только для типа данных TIMESTAMP и нет для других типов, таких как DATETIME.)

По умолчанию текущий часовой пояс для каждого подключения - время сервера. Часовой пояс можно установить для каждого соединения, как описано в Поддержка часовых поясов сервера MySQL.

эта презентация OReilly очень хороша для этой темы (извините, PDF) cdn.oreillystatic.com/en/assets/1/event/36/…

gcb 27.10.2013 06:11

Также о характере мероприятия: - видеоконференция (TIMESTAMP). Все сопровождающие должны видеть ссылку на абсолютный момент времени, скорректированный с учетом его часового пояса. - Местное время задачи (DATETIME), я должен выполнить эту задачу 31.03.2014 в 9:00 утра. Неважно, работаю ли я в этот день в Нью-Йорке или Париже. Я начну работать в 8:00 по местному времени, в месте, где я буду в этот день.

yucer 17.12.2013 14:40

Основное отличие состоит в том, что DATETIME является постоянным, в то время как TIMESTAMP зависит от настройки time_zone.

Так что это имеет значение только тогда, когда у вас есть - или, возможно, в будущем - синхронизированные кластеры по часовым поясам.

Проще говоря: Если у меня есть база данных в Австралии и я сделаю дамп этой базы данных для синхронизации / заполнения базы данных в Америке, тогда TIMESTAMP будет обновляться, чтобы отражать реальное время события в новом часовом поясе, а DATETIME все равно будет отражать время. события в часовом поясе au.

Отличным примером использования DATETIME там, где следовало бы использовать TIMESTAMP, является Facebook, где их серверы никогда не могут точно знать, какое время произошло в разных часовых поясах. Однажды у меня был разговор, в котором время сказал, что я отвечаю на сообщения до того, как сообщение было отправлено. (Это, конечно, также могло быть вызвано неправильным переводом часового пояса в программе обмена сообщениями, если время публиковалось, а не синхронизировалось.)

Я не думаю, что это хороший способ мышления. Я бы просто сохранил и обработал все даты в формате UTC и убедился, что интерфейс отображает их в соответствии с заданным часовым поясом. Такой подход прост и предсказуем.

Kos 03.03.2012 14:51

@Kos: не хранит и не обрабатывает все даты в UTC, что именно TIMESTAMP делает внутри? (Затем преобразовать его для отображения вашего местного часового пояса?)

carbocation 09.12.2013 09:49
мой местный часовой пояс? Как ваша БД узнает мой часовой пояс? ;-) Обычно между базой данных и пользовательским интерфейсом происходит некоторая обработка. Локализацию делаю только после всей обработки.
Kos 09.12.2013 14:14

@Koz: моя база данных не знает часовой пояс вашей базы данных:! Но он знает метку времени. Ваша база данных знает свой собственный часовой пояс и применяет его при интерпретации / представлении метки времени. 1:01 11 декабря 2013 г. в Пекине, Китай - это не то же самое время, что и 1:01 11 декабря 2013 г. в Сиднее, Австралия. Google: «часовые пояса» и «нулевой меридиан».

ekerner 10.12.2013 18:35

TIMESTAMP всегда находится в формате UTC (то есть в секундах, прошедших с 01.01.1970, в UTC), и ваш сервер MySQL автоматически преобразует его в дату / время для часового пояса соединения. В долгосрочной перспективе TIMESTAMP - лучший способ, потому что вы знаете, что ваши временные данные всегда будут в формате UTC. Например, вы не испортите даты, если перейдете на другой сервер или измените настройки часового пояса на своем сервере.

Примечание: часовой пояс соединения по умолчанию - это часовой пояс сервера, но его можно (нужно) изменять за сеанс (см. SET time_zone = ...).

На самом деле, зависит от приложения.

Рассмотрите возможность установки пользователем метки времени на сервере в Нью-Йорке для встречи в Сангае. Теперь, когда пользователь подключается в Sanghai, он получает доступ к той же метке времени встречи с зеркального сервера в Токио. Он увидит встречу по токийскому времени, смещенному от исходного нью-йоркского времени.

Поэтому для значений, которые представляют время пользователя, например, встречи или расписания, лучше использовать datetime. Это позволяет пользователю контролировать точную дату и время, независимо от настроек сервера. Установленное время - это установленное время, на которое не влияет часовой пояс сервера, часовой пояс пользователя или изменения в способе расчета летнего времени (да, оно меняется).

С другой стороны, для значений, представляющих системное время, таких как платежные операции, изменения таблиц или ведение журнала, всегда используйте отметки времени. На систему не повлияет перемещение сервера в другой часовой пояс или сравнение серверов в разных часовых поясах.

Отметки времени также меньше в базе данных и быстрее индексируются.

Ваше приложение не должно полагаться на часовой пояс сервера. Приложение должно ВСЕГДА выбирать часовой пояс в сеансе соединения с базой данных, которое оно использует, перед отправкой любого запроса. Если соединение используется несколькими пользователями (например, webapp), используйте UTC и выполните преобразование часового пояса на стороне рендеринга.

dolmen 21.05.2019 19:29

Мне нравится временная метка Unix, потому что вы можете преобразовать в числа и просто беспокоиться о числе. Плюс вы добавляете / вычитаете и получаете продолжительность и т. д. Затем конвертируете результат в Date в любом формате. Этот код определяет, сколько времени в минутах прошло между отметкой времени из документа и текущим временем.

$date  = $item['pubdate']; (etc ...)
$unix_now = time();
$result = strtotime($date, $unix_now);
$unix_diff_min = (($unix_now  - $result) / 60);
$min = round($unix_diff_min);

Или используйте удобочитаемую и родную дату и время MySQL и используйте собственные функции MySQL для добавления / вычитания даты и времени.

Julien Palard 25.04.2013 14:01

Приведенные ниже примеры показывают, как тип даты TIMESTAMP изменил значения после изменения time-zone to 'america/new_york', где DATETIME не изменился.

mysql> show variables like '%time_zone%';
+------------------+---------------------+
| Variable_name    | Value               |
+------------------+---------------------+
| system_time_zone | India Standard Time |
| time_zone        | Asia/Calcutta       |
+------------------+---------------------+

mysql> create table datedemo(
    -> mydatetime datetime,
    -> mytimestamp timestamp
    -> );

mysql> insert into datedemo values ((now()),(now()));

mysql> select * from datedemo;
+---------------------+---------------------+
| mydatetime          | mytimestamp         |
+---------------------+---------------------+
| 2011-08-21 14:11:09 | 2011-08-21 14:11:09 |
+---------------------+---------------------+

mysql> set time_zone = "america/new_york";

mysql> select * from datedemo;
+---------------------+---------------------+
| mydatetime          | mytimestamp         |
+---------------------+---------------------+
| 2011-08-21 14:11:09 | 2011-08-21 04:41:09 |
+---------------------+---------------------+

Я превратил свой ответ в статью, чтобы больше людей могли найти это полезным, MySQL: типы данных Datetime и Timestamp.

Ну, на самом деле эффективное время DATETIME изменилось с изменением часового пояса, TIMESTAMP не изменилось, но человеческое представление изменилось.

flindeberg 04.07.2014 11:56

Я обнаружил непревзойденную полезность способности TIMESTAMP автоматически обновлять себя на основе текущего времени без использования ненужных триггеров. Это только я, хотя TIMESTAMP - это UTC, как было сказано.

Он может отслеживать в разных часовых поясах, поэтому, если вам, например, нужно отображать относительное время, время в формате UTC - это то, что вам нужно.

Я всегда использую временную метку Unix, просто для сохранения здравомыслия при работе с большим количеством информации о дате и времени, особенно при выполнении корректировок часовых поясов, добавлении / вычитании дат и т. д. При сравнении временных меток это исключает усложняющие факторы часового пояса и позволяет сэкономить ресурсы при обработке на стороне сервера (будь то код приложения или запросы к базе данных), поскольку вы используете легкую арифметику, а не более тяжелую дату и время, добавляя / вычитая функции.

Еще одна вещь, на которую стоит обратить внимание:

Если вы создаете приложение, вы никогда не знаете, как ваши данные могут быть использованы в дальнейшем. Если вам придется, скажем, сравнить кучу записей в вашем наборе данных, скажем, с кучей элементов из стороннего API, и, скажем, поместить их в хронологическом порядке, вы будете счастливы получить Метки времени Unix для ваших строк. Даже если вы решите использовать метки времени MySQL, сохраните метку времени Unix в качестве страховки.

Стоит отметить, что в MySQL вы можете использовать что-то вроде приведенных ниже строк при создании столбцов таблицы:

on update CURRENT_TIMESTAMP

Это будет обновлять время при каждом изменении строки и иногда очень полезно для сохраненной информации о последнем редактировании. Это работает только с отметкой времени, но не с датой и временем.

По моему опыту, если вам нужно поле даты, в которое вставка выполняется только один раз, и вы не хотите, чтобы в этом конкретном поле выполнялись какие-либо обновления или какие-либо другие действия, используйте дата время.

Например, рассмотрим таблицу user с полем ДАТА РЕГИСТРАЦИИ. В этой таблице user, если вы хотите узнать время последнего входа в систему конкретного пользователя, выберите поле типа отметка времени, чтобы поле обновлялось.

Если вы создаете таблицу из phpMyAdmin, настройка по умолчанию обновит поле отметка времени, когда произойдет обновление строки. Если ваше поле временной метки не обновляется при обновлении строки, вы можете использовать следующий запрос, чтобы поле отметка времени обновлялось автоматически.

ALTER TABLE your_table
      MODIFY COLUMN ts_activity TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;

Тип данных timestamp хранит дату и время, но в формате UTC, а не в формате текущего часового пояса, как datetime. И когда вы получаете данные, временная метка снова преобразует их в текущее время часового пояса.

Итак, предположим, что вы находитесь в США и получаете данные с сервера с часовым поясом США. Тогда вы получите дату и время в соответствии с часовым поясом США. Столбец типа данных timestamp всегда обновляется автоматически при обновлении его строки. Поэтому может быть полезно отслеживать, когда конкретная строка обновлялась в последний раз.

Для более подробной информации вы можете прочитать сообщение в блоге Отметка времени против даты и времени.

Вы можете (должны) всегда определять часовой пояс на уровне сеанса с помощью SET time_zone = '+0:00'; (здесь UTC), чтобы быть уверенным, что вы получаете / устанавливаете из значений TIMESTAMP, и избегайте зависимости от значения по умолчанию time_zone сервера, которое может измениться.

dolmen 09.10.2019 17:47

Остерегайтесь изменения метки времени при выполнении инструкции UPDATE для таблицы. Если у вас есть таблица со столбцами 'Name' (varchar), 'Age' (int) и 'Date_Added' (timestamp), и вы запускаете следующий оператор DML

UPDATE table
SET age = 30

тогда каждое значение в столбце Date_Added будет изменено на текущую метку времени.

в зависимости от того, как вы настраиваете свою таблицу, вы можете контролировать это поведение. посмотрите на dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.htm‌ l

Charles Faiga 07.03.2014 16:03

@CharlesFaiga По умолчанию метка времени обновляется при обновлении любого другого столбца. Вы должны явно отключить это, если хотите, чтобы метка времени сохранила свое исходное значение.

Lloyd Banks 09.03.2014 02:35

Что это такое ?! вы должны установить столбец отметки времени на ON UPDATE CURRENT_TIMESTAMP

Accountant م 02.09.2019 21:59

Это характерная черта, который вы должны явно включить при создании таблицы.

dolmen 09.10.2019 17:49
  1. TIMESTAMP составляет четыре байта против восьми байтов для DATETIME.

  2. Отметки времени также меньше в базе данных и быстрее индексируются.

  3. Тип DATETIME используется, когда вам нужны значения, содержащие информацию о дате и времени. MySQL извлекает и отображает значения DATETIME в формате «ГГГГ-ММ-ДД ЧЧ: ММ: СС». Поддерживаемый диапазон: от '1000-01-01 00:00:00' до '9999-12-31 23:59:59'.

Тип данных TIMESTAMP имеет диапазон от '1970-01-01 00:00:01' UTC до '2038-01-09 03:14:07' UTC. Он имеет разные свойства в зависимости от версии MySQL и режима SQL, в котором работает сервер.

  1. DATETIME является постоянным, в то время как TIMESTAMP зависит от параметра time_zone.

Вам необходимо прояснить # 4: временная метка в том виде, в каком она хранится, является постоянной и не относительной (полностью независимой) от часового пояса, в то время как отображаемый результат при извлечении зависит от часового пояса запрашивающего сеанса. DATETIME всегда относится к часовому поясу, в котором оно было записано, и всегда должно учитываться в этом контексте - ответственность, которая теперь ложится на приложение.

Christopher McGowan 28.01.2016 01:32

Отличный ответ. Чтобы добавить к этому ответу, если мы попытаемся сохранить значения за пределами этого '2038-01-09 03:14:07', мы либо получим ошибку, либо сохраним ее как '0000-00-00 00:00:00'. Я получал эту ошибку для своей базы данных, поскольку она имеет сдвинутые во времени значения (для целей шифрования).

KarthikS 28.02.2017 09:28

Кроме того, существует проблема с DATETIME со значением DEFAULT в версиях mysql ниже 5.5. dba.stackexchange.com/questions/132951/…

Velaro 25.02.2019 16:42

Еще одно различие между Timestamp и Datetime заключается в Timestamp, вы не можете использовать значение по умолчанию NULL.

Это явно неверно. Вот пример:CREATE TABLE t2 ( ts1 TIMESTAMP NULL, ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP); Первый столбец может принимать значение NULL.

Ormoz 28.04.2015 12:36

Основное различие в том, что

  • ИНДЕКС на отметке времени - работает
  • ИНДЕКС по дате и времени - Не работает

посмотри на этот опубликовать, чтобы увидеть проблемы с индексацией Datetime

У обоих есть одна и та же проблема, если вы выбираете с помощью функции на основе значения столбца, и оба могут быть проиндексированы.

Marcus Adams 19.02.2015 22:05

Индекс работает по метке времени и не работает по дате и времени? Вы сделали неверные выводы из этих сообщений.

Salman A 03.03.2015 07:59

Я рекомендую использовать ни один в поле DATETIME или TIMESTAMP. Если вы хотите представить конкретный день в целом (например, день рождения), используйте тип DATE, но если вы говорите более конкретно, вы, вероятно, заинтересованы в записи фактического момента, а не единицы измерения. время (день, неделя, месяц, год). Вместо использования DATETIME или TIMESTAMP используйте BIGINT и просто сохраните количество миллисекунд с начала эпохи (System.currentTimeMillis (), если вы используете Java). Это дает несколько преимуществ:

  1. Вы избегаете привязки к поставщику. Практически каждая база данных поддерживает целые числа относительно похожим образом. Предположим, вы хотите перейти в другую базу данных. Хотите ли вы беспокоиться о различиях между значениями DATETIME MySQL и тем, как Oracle их определяет? Даже среди разных версий MySQL TIMESTAMPS имеют разный уровень точности. Только недавно MySQL поддерживал миллисекунды в метках времени.
  2. Нет проблем с часовым поясом. Здесь были содержательные комментарии о том, что происходит с часовыми поясами с разными типами данных. Но насколько это общеизвестно, и найдут ли все ваши коллеги время, чтобы изучить это? С другой стороны, довольно сложно испортить замену BigINT на java.util.Date. Использование BIGINT приводит к тому, что многие проблемы с часовыми поясами уходят на второй план.
  3. Не беспокойтесь о диапазонах или точности. Вам не нужно беспокоиться о том, что будет сокращено в будущих диапазонах дат (TIMESTAMP идет только до 2038 года).
  4. Интеграция сторонних инструментов. Использование целого числа тривиально для сторонних инструментов (например, EclipseLink) для взаимодействия с базой данных. Не все сторонние инструменты будут понимать «дату и время» так же, как MySQL. Хотите попробовать выяснить в Hibernate, следует ли использовать объект java.sql.TimeStamp или java.util.Date, если вы используете эти настраиваемые типы данных? Использование ваших базовых типов данных делает использование сторонних инструментов тривиальным.

Этот вопрос тесно связан с тем, как вы должны хранить денежную ценность (например, 1,99 доллара США) в базе данных. Что вы должны использовать: Decimal, или тип базы данных Money, или, что хуже всего, Double? Все три варианта ужасны по многим причинам, перечисленным выше. Решение состоит в том, чтобы хранить стоимость денег в центах с помощью BIGINT, а затем конвертировать центы в доллары, когда вы показываете значение пользователю. Работа базы данных - хранить данные, а НЕ интерпретировать эти данные. Все эти причудливые типы данных, которые вы видите в базах данных (особенно в Oracle), мало что добавляют и подталкивают вас к привязке к поставщику.

Мне нравится это решение. Срок действия TIMESTAMP, истекающий в 2038 году, является серьезной проблемой. Это не так уж и далеко!

Charlie Dalsass 12.05.2015 19:10

@CharlieDalsass Как вы думаете, в этот раз будет актуальное программное обеспечение :-P

Mohammed H 21.05.2015 20:09

Я в проблемы с TIMESTAMP. Эта альтернатива BIGINT кажется лучше.

KcFnMi 26.07.2015 11:43

Я тоже выбрал Бигинт. Хранение дешевое. Frontend создает любую запись даты, которую вы хотите. Запрос диапазонов - не проблема (нужен определенный день, запросить диапазон). Очень совместим с любой системой.

Riël 17.12.2015 01:09

Это затрудняет запрос данных по дате, если они хранятся в миллисекундах.

Ali Saeed 21.12.2015 18:55

Это действительно лучшее решение, если вы заботитесь о переносимости и работе с пользователями в нескольких часовых поясах или в базе данных в другом часовом поясе, чем пользователи. TIMESTAMP может быть подходящим вариантом, если в нем нет недостатков дизайна. Жаль, что неработающие решения получили больше голосов, потому что были опубликованы раньше (годами!).

German 03.01.2016 04:20

Несомненно, это лучшее решение, но я рекомендую сохранять в секундах, а не в миллисекундах. В любом случае: нет проблем с часовым поясом, нет проблем в будущем, это абсолютно относительно сервера / данных, но может быть легко локализовано. Аналогичной альтернативой было бы хранить дату / время ISO как varchar, но использование BIGINT потребляет меньше места и упрощает математику даты / времени.

yahermann 16.09.2016 23:50

Отличное решение! И вы совершенно правы, что вас "заперли". Когда вы приобретаете привычку позволять другим «делать работу за вас», вы начинаете терять детали, которые делают ВАС программистом.

fmc 22.02.2017 12:29

Это решение превращает развитие в кошмар. И когда вы смотрите свои необработанные данные базы данных, вы получаете абсурдные целые числа.

PHPst 11.11.2017 08:59

@PHPst можешь подробно рассказать об абсурде? Как упорядоченные целые числа - это кошмар? Для интервалов дат также работает BETWEEN ... Если вам нужно проверить конкретную дату, вы можете использовать для преобразования языки стороннего / клиентского сервера или онлайн-сервис (например, преобразователь эпох) ...

CPHPython 26.04.2018 18:16

Спасибо за ваш комментарий. Проблема в том, что если вам нужно проверить конкретную дату, вы должны либо использовать языки стороннего / клиентского сервера для преобразования, либо онлайн-службу. Очевидно, что это менее эффективно, чем ввод даты в обычном формате. Типоральные данные не зря используются в RDBM.

PHPst 27.04.2018 03:06

@yahermann Использование секунд вместо миллисекунд снижает точность как минимум на два (три?) порядка. (Если в течение одной секунды происходит несколько событий, вы не можете гарантировать, что метки времени уникальны. Следовательно, метку времени нельзя использовать в качестве первичного ключа, требуя дополнительного столбца AUTOINCREMENT в качестве PK.) Конечно, это также верно, если вам нужна точность в микросекундах или наносекундах для критичного ко времени кода.

Agi Hammerthief 23.08.2018 11:27

Просто используйте вместо него datetime(6). Проблемы с часовым поясом на самом деле не имеют значения, если вы указываете часовой пояс при вставке. MySql всегда сохраняет datetime как UTC 0 на диске. Он преобразует его в часовой пояс контекста соединения при чтении. Это довольно просто сделать "правильно", особенно при использовании грамотного ORM.

Ryan 16.07.2019 07:00

@ Райан - эээ, нет. Проверьте свой источник. timestamp преобразован, datetime преобразован в нет. dev.mysql.com/doc/refman/5.5/en/….

ToolmakerSteve 28.10.2019 15:58

Ссылка взята из этой статьи:

Основные отличия:

TIMESTAMP используется для отслеживания изменений в записях и обновления каждый раз при изменении записи. DATETIME используется для хранения определенного и статического значения, на которое не влияют никакие изменения в записях.

TIMESTAMP также зависит от других настроек, связанных с ЧАСОВЫМ ПОЯСОМ. DATETIME постоянно.

TIMESTAMP внутренне преобразовал текущий часовой пояс в UTC для хранения, а во время извлечения преобразовал обратно в текущий часовой пояс. DATETIME не может этого сделать.

Поддерживаемый диапазон TIMESTAMP: «1970-01-01 00:00:01» UTC по «2038-01-19 03:14:07» UTC. Поддерживаемый диапазон DATETIME: С «1000-01-01 00:00:00» по «9999-12-31 23:59:59»

2016 +: я советую установить часовой пояс Mysql на UTC и использовать DATETIME:

Любая недавняя интерфейсная среда (Angular 1/2, react, Vue, ...) может легко и автоматически преобразовать дату и время UTC в местное время.

Кроме того:

(Если вы, вероятно, не измените часовой пояс своих серверов)


Пример с AngularJs

// back-end: format for angular within the sql query
SELECT DATE_FORMAT(my_datetime, "%Y-%m-%dT%TZ")...

// font-end Output the localised time
{{item.my_datetime | date :'medium' }}

Все локализованные форматы времени доступны здесь: https://docs.angularjs.org/api/ng/filter/date

Ваши данные не должны быть привязаны к настройкам часового пояса ваших серверов. Возможно, это сработает для вас, если у вас есть один ящик MySql под вашим столом

Jin 06.05.2016 18:58

@Jin UTC означает отсутствие часового пояса, такого как TIMESTAMP. Если все ваши серверы в UTC, проблем нет. Возможно, у вас не работает, если у вас конфиг 2000-х годов.

Sebastien Horin 06.05.2016 21:05

В будущем TIMESTAMP может быть обновлен до 64-битного значения. Тогда больше нет проблем.

twicejr 21.09.2017 13:58

Загрузка целых сторонних библиотек, чтобы поймать что-то подобное, тоже не так уж хороша для производительности, не так ли? Учитывая, что это на стороне клиента и не влияет на вашу базу данных ... Тем не менее, все, что вы делаете на стороне клиента, БУДЕТ требовать проверки на стороне сервера. Итак, если подумать о картине полный, действительно ли это помогает с проблемой скорости? - Эти тесты, кстати, немного странные, мне кажется. Использование строки в запросе для сравнения полей отметок времени также кажется довольно странным. Это тоже должно повредить производительности, не так ли?

NoobishPro 20.12.2017 06:41

@Babydead, очевидно, вы не собираетесь загружать библиотеку только для преобразования даты, но использование внешней среды - хорошая практика для современного и чистого кода.

Sebastien Horin 20.12.2017 16:18

Ну, я только хотел сказать, что принимать какой-либо стандарт из-за стороннего решения - плохо. Я не собираюсь начинать обсуждение того, является ли использование таких фреймворков хорошей практикой (с чем я не согласен). Я считаю, что речь идет о том, что лучше всего с php и почему. Добавление сторонних плагинов меняет все игры и перспективы. Это может превратиться в бесконечную дискуссию.

NoobishPro 20.12.2017 23:52

В любом случае @Babydead, даже если вы не хотите использовать фреймворк, преобразовать время UTC в местное время проще, чем между двумя разными часовыми поясами в целом.

Sebastien Horin 21.12.2017 01:00

Не полагайтесь в своем приложении на часовой пояс сервера. Вместо этого определите time_zone для использования при каждом подключении к базе данных: SET time_zone = '+0:00'; для UTC.

dolmen 09.10.2019 17:42

Я просто использую неподписанный BIGINT при сохранении UTC ...

которое затем все еще можно настроить на местное время в PHP.

DATETIME должен быть выбран вместе с FROM_UNIXTIME( integer_timestamp_column ).

очевидно, что следует установить индекс для этого столбца, иначе не было бы никакого продвижения.

TIMESTAMP требует 4 байта, тогда как DATETIME требует 8 байтов.

Многие ответы здесь предлагают хранить как временную метку, если вы должны представлять четко определенные моменты времени. Но вы также можете иметь точки во времени с datetime, если вы по соглашению храните их все в формате UTC.

Можете ли вы назвать несколько причин, по которым я должен предпочесть это вместо использования метки времени?

Jasir 12.08.2016 11:02

@Jasir не совсем, кажется, это большая дискуссия. Я только указывал, что datetime может представлять определенные моменты времени, если существует соглашение о хранении всех datetime в определенном часовом поясе (например, UTC). Лично я бы сохранил все в datetime, timestamp ограничен 2038 (хотя я предполагаю, что они в конечном итоге что-то с этим сделают), и если я посмотрю на некоторые необработанные данные в БД, datetime будет читаемым без необходимости применять преобразование. Опять же, это очень субъективно.

Matthew 12.08.2016 14:41

@Matthew Но если сеанс time_zone тоже не UTC, у вас будут сюрпризы (ошибки), если вы будете использовать функции даты и времени MySQL, такие как NOW(), DATE_ADD, без предварительного преобразования часового пояса ... Так зачем же усложнять взаимодействие с базой данных, чем необходимо?

dolmen 09.10.2019 18:06

@dolmen идея в том, что на стороне сервера все в формате UTC. Включен часовой пояс сеанса MySQL. Это должно быть установлено как часовой пояс сервера, который должен быть UTC.

Matthew 10.10.2019 04:54

TIMESTAMP полезен, когда у вас есть посетители из разных стран с разными часовыми поясами. вы можете легко преобразовать TIMESTAMP в часовой пояс любой страны

Пока не упомянуто, что DEFAULT CURRENT_TIMESTAMP работает только с полями типа Timestamp, но не с полями типа DateTime.

Это становится актуальным для таблиц MS Access, которые могут использовать только DateTime, но не Timestamp.

Поддержка DEFAULT CURRENT_TIMESTAMP для DATETIME добавлена ​​в MySQL 5.6.

Sarath Sadasivan Pillai 27.03.2017 10:59

«Любой из синонимов CURRENT_TIMESTAMP имеет то же значение, что и CURRENT_TIMESTAMP. Это CURRENT_TIMESTAMP(), NOW(), LOCALTIME, LOCALTIME(), LOCALTIMESTAMP и LOCALTIMESTAMP()». -> документы MySQL

CPHPython 26.04.2018 18:20

В моем случае я устанавливаю UTC в качестве часового пояса для всего: системы, сервера базы данных и т. д. Каждый раз, когда могу. Если моему клиенту требуется другой часовой пояс, я настраиваю его в приложении.

Я почти всегда предпочитаю метки времени, а не поля даты и времени, потому что метки времени неявно включают часовой пояс. Итак, с того момента, как к приложению будут обращаться пользователи из разных часовых поясов, и вы хотите, чтобы они видели дату и время в своем местном часовом поясе, этот тип поля позволяет сделать это довольно легко, чем если бы данные были сохранены в полях datetime. .

В качестве плюса, в случае миграции базы данных в систему с другим часовым поясом, я буду чувствовать себя более уверенно, используя временные метки. Не говоря уже о возможных проблемах при вычислении разницы между двумя моментами с летним изменением времени между ними и необходимостью точности в 1 час или меньше.

Итак, подытоживая, я ценю следующие преимущества временной метки:

  • готов к использованию в международных (несколько часовых поясах) приложениях
  • легкая миграция между часовыми поясами
  • довольно легко вычислить разницу (просто вычтите обе временные метки)
  • не беспокойтесь о датах в / из летнего периода

По всем этим причинам я выбираю поля UTC и отметки времени, где это возможно. И я избегаю головной боли;)

Данные timestamp будут интересны человеку, обслуживающему ваше приложение, когда наступит 20 января 2038 года. тик-так тик-так

Wilson Hauck 10.05.2019 18:28

Затем тип временной метки можно увеличить на бит и удвоить возможные значения.

Roger Campanera 02.07.2019 17:33

Проверьте свою теорию, чтобы «немного увеличиться», и посмотрите, сможете ли вы успешно сохранить данные 1 февраля 2038 года и получить их с помощью MySQL. Когда закончите, давайте посмотрим на определение вашей таблицы, пожалуйста. Вероятно, в феврале 2038 года у вас будет много несчастливых прошлых знакомых.

Wilson Hauck 02.07.2019 22:58

@WilsonHauck В любом случае вам придется обновить версию MySQL задолго до 2038 года. И этот расширенный TIMESTAMP будет обрабатываться миграцией. Кроме того, несколько приложений, помимо обработки ипотечных кредитов, действительно должны заботиться о 2038 году прямо сейчас.

dolmen 09.10.2019 17:55

На многие инструменты и материалы профессионального уровня @dolmen предоставляется гарантия более 20 лет. Так что что-то вроде warranties.expires_at не могло быть меткой времени MySQL сегодня.

alexw 25.05.2020 19:09

Сравнение DATETIME, TIMESTAMP и DATE

Что это за [.fraction]?

  • Значение DATETIME или TIMESTAMP может включать конечную дробную часть часть секунд с точностью до микросекунд (6 цифр). В в частности, любая дробная часть в значении, вставленном в DATETIME или столбец TIMESTAMP сохраняется, а не отбрасывается. Это, конечно, необязательно.

Источники:

+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+
|                                       TIMESTAMP                                       |                                 DATETIME                                 |
+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+
| TIMESTAMP requires 4 bytes.                                                           | DATETIME requires 8 bytes.                                               |
| Timestamp is the number of seconds that have elapsed since January 1, 1970 00:00 UTC. | DATETIME is a text displays 'YYYY-MM-DD HH:MM:SS' format.                |
| TIMESTAMP supported range: ‘1970-01-01 00:00:01′ UTC to ‘2038-01-19 03:14:07′ UTC.    | DATETIME supported range: ‘1000-01-01 00:00:00′ to ‘9999-12-31 23:59:59′ |
| TIMESTAMP during retrieval converted back to the current time zone.                   | DATETIME can not do this.                                                |
| TIMESTAMP is used mostly for metadata i.e. row created/modified and audit purpose.    | DATETIME is used mostly for user-data.                                   |
+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+

timestamp - текущее время события, записанного компьютером через Сетевой протокол времени (NTP).

datetime - это текущий часовой пояс, установленный в вашей конфигурации PHP.

Нет. Не имеет отношения к NTP.

dolmen 09.10.2019 18:16

Я перестал использовать datetime в своих приложениях после того, как столкнулся с множеством проблем и ошибок, связанных с часовыми поясами. ИМХО использование timestamp лучше, чем datetime в большинстве случаев.

Когда вы спрашиваете, сколько времени? и ответ будет примерно таким: «2019-02-05 21:18:30», это не завершенный, не определенный ответ, потому что ему не хватает другой части, в каком часовом поясе? Вашингтон? Москва ? Пекин?

Использование даты без часового пояса означает, что ваше приложение работает только с 1 часовым поясом, однако временные метки дают вам преимущества datetime, а также гибкость отображения одного и того же точного момента времени в разных часовых поясах.

Вот несколько случаев, которые заставят вас пожалеть об использовании datetime и пожелать, чтобы ваши данные хранились в метках времени.

  1. Для удобства клиентов вы хотите показывать им время, основанное на их предпочтительных часовых поясах, не заставляя их делать математику и переводить время в их значимый часовой пояс. все, что вам нужно, это изменить часовой пояс, и весь код вашего приложения будет таким же.

    SET time_zone = '+2:00';
    
  2. вы изменили страну, в которой находитесь, и продолжаете работу по сохранению данных, просматривая их в другом часовом поясе (без изменения фактических данных).

  3. вы принимаете данные от разных клиентов по всему миру, каждый из которых вставляет время в свой часовой пояс.

Коротко

datetime = приложение поддерживает 1 часовой пояс (как для вставки, так и для выбора)

timestamp = приложение поддерживает любой часовой пояс (как для вставки, так и для выбора)


Этот ответ предназначен только для того, чтобы выделить гибкость и простоту использования временных меток, когда дело доходит до часовых поясов, он не охватывает никаких других различий, таких как размер столбца, диапазон или дробь.

что, если есть поля, которые используют date, а другое поле использует timestamp в одной таблице. Я думаю, это вызовет новую проблему, потому что данные, отфильтрованные where, не соответствуют изменениям часового пояса.

Erlang P 11.02.2020 03:44

@ErlangP В этом случае ваше приложение должно исправить проблему часового пояса в столбце date перед отправкой запроса.

Accountant م 11.02.2020 13:17

Если вы хотите ГАРАНТИРОВАТЬ, что ваше приложение НЕ будет работать в феврале 2038 года, используйте TIMESTAMP. Обратитесь к вашему REFMAN для получения информации о ДИАПАЗОНЕ поддерживаемых дат.

2038 - это пока что вы изменили версию сервера MySQL на версию, которая поддерживает расширенный TIMESTAMP задолго до этого. И это также предполагает, что ваше приложение все еще будет использоваться.

dolmen 09.10.2019 18:09

DATETIME не несет с собой информации о часовом поясе и всегда будет отображать то же самое независимо от часового пояса, действующего для сеанса, который по умолчанию соответствует часовому поясу сервера, если вы явно не изменили его. Однако, если я инициализирую столбец DATETIME с помощью функции, такой как NOW(), а не литерала, такого как '2020-01-16 12:15:00', то сохраненное значение, конечно же, будет текущей датой и временем, локализованными в часовом поясе сеанса.

TIMESTAMP, напротив, неявно переносит информацию о часовом поясе: когда вы инициализируете столбец TIMESTAMP значением, это значение преобразуется в UTC перед сохранением. Если сохраняемое значение является литералом, например '2020-01-16 12:15:00', оно интерпретируется как находящееся в текущем часовом поясе сеанса для целей преобразования. И наоборот, когда отображается столбец TIMESTAMP, он сначала будет преобразован из UTC в текущий часовой пояс сеанса.

Когда использовать то или другое? Пример из практики

Веб-сайт общественной театральной труппы представляет несколько спектаклей, билеты на которые продаются. Дата и время этих представлений появятся в раскрывающемся списке, из которого покупатель, желающий купить билеты на представление, выберет один. Было бы разумно, чтобы столбец базы данных performance_date_and_time был типа DATETIME. Если выступление проводится в Нью-Йорке, подразумевается, что здесь задействован неявный часовой пояс («местное время Нью-Йорка»), и в идеале мы хотели бы, чтобы дата и время отображались как «12 декабря 2019 года в 20:00». независимо от часового пояса сеанса и без необходимости выполнять какие-либо преобразования часового пояса.

С другой стороны, после начала выступления 12 декабря 2019 года в 20:00 мы, возможно, больше не захотим продавать билеты на него и, следовательно, больше не будем отображать это выступление в раскрывающемся списке. Итак, мы хотели бы знать, произошло ли '2019-12-12 20:00:00' или нет. Это было бы аргументом в пользу наличия столбца TIMESTAMP, установки часового пояса для сеанса на «Америка / Нью-Йорк» с set session time_zone='America/New_York' и последующего сохранения '2019-12-12 20:00:00' в столбце TIMESTAMP. Отныне мы можем проверить, началась ли производительность, сравнив этот столбец с NOW() независимо от часового пояса текущего сеанса.

Или может иметь смысл иметь столбцы DATETIME и TIMESTAMP для этих двух отдельных целей. Или нет. Ясно, что любой из них может служить обеим целям. Если вы используете только столбец DATETIME, то перед сравнением с NOW() вы должны установить текущий часовой пояс в соответствии с вашим местным часовым поясом. Если вы используете только столбец TIMESTAMP, вы должны установить часовой пояс сеанса на ваш местный часовой пояс перед отображением столбца.

Для значений TIMESTAMP, но также для функций даты и времени MySQL важен не серверtime_zone, а сессияtime_zone (который по умолчанию имеет значение серверtime_zone, пока не будет изменено явно). Никогда не полагайтесь в своем приложении на настройки по умолчанию, которые могут измениться.

dolmen 09.10.2019 18:14

@dolmen Конечно, вы правы, но мы говорим о семантике. В своем ответе я говорю: "... setting the the server's timezone for the session ...".. Возможно, это можно было бы выразить более четко, просто сказав «установка часового пояса для сеанса», но, в конце концов, это будет часовой пояс, который будет использовать сервер. Я обновлю ответ, чтобы было понятнее.

Booboo 09.10.2019 18:19

Ни один. Типы DATETIME и TIMESTAMP принципиально не подходят для общих вариантов использования. MySQL изменит их в будущем. Вам следует использовать метки времени BIGINT и UNIX, если у вас нет особой причины использовать что-то еще.

Особые случаи

Вот некоторые конкретные ситуации, когда ваш выбор проще, и вам не нужны анализ и общие рекомендации в этом ответе.

  • Только дата - если вас волнует только дата (например, дата следующего лунного Нового года, 25.02.2020) И у вас есть четкое представление о том, в каком часовом поясе применяется эта дата (или вам все равно, как в случае с Лунный Новый год), затем используйте тип столбца DATE.

  • Запись времени вставки - если вы регистрируете дату / время вставки для строк в своей базе данных, И вам все равно, что ваше приложение сломается в следующие 19 лет, тогда продолжайте и используйте TIMESTAMP со значением по умолчанию CURRENT_TIMESTAMP().

Почему сломан TIMESTAMP?

Тип TIMESTAMP хранится на диске в часовом поясе UTC. Это означает, что если вы физически переместите свой сервер, он не сломается. Это хорошо ✅. Но временные метки, как они определены в настоящее время, полностью перестанут работать в 2038 году.

Каждый раз, когда вы INSERT INTO или SELECT FROM столбец TIMESTAMP, учитывается физическое местоположение (т.е. конфигурация часового пояса) вашего клиента / сервера приложений. Если вы переместите сервер приложений, ваши даты сломаются ❌.

Почему сломан DATETIME?

DATETIME хранит DATE и TIME в одном столбце. Ни одна из этих вещей не имеет никакого значения, если часовой пояс не понятен, и часовой пояс нигде не сохраняется ❌. Вы должны указать предполагаемый часовой пояс в качестве комментария в столбце, потому что часовой пояс неразрывно связан с данными. Так мало людей используют комментарии к столбцам, поэтому это ожидаемая ошибка. Я унаследовал сервер из Аризоны, поэтому мне всегда нужно преобразовывать все временные метки из времени Аризоны, а затем в другое время.

Единственная ситуация, в которой DATETIME верна, - это завершить это предложение:

Your year 2020 solar new year starts at exactly DATETIME("2020-01-01 00:00:00").

Другого хорошего использования DATETIME нет. Возможно, вы представите себе веб-сервер для городского правительства в Делавэре. Конечно, можно предположить, что часовой пояс для этого сервера и всех людей, обращающихся к нему, находится в Делавэре, с Восточным часовым поясом, верно? Неправильный! В этом тысячелетии все мы думаем о серверах как о существующих в «облаке». Поэтому всегда неправильно думать о вашем сервере в каком-либо конкретном часовом поясе, потому что ваш сервер когда-нибудь будет перемещен.

Примечание: MySQL теперь поддерживает смещение часового пояса в литералах DATETIME (спасибо @Marko). Это может сделать установку DATETIME более удобной для вас, но не устраняет неполный и, следовательно, бесполезный смысл данных, обозначение этой фатальной проблемы («❌») выше.

Как использовать BIGINT?

Определять:

CREATE TEMPORARY TABLE good_times (
    a_time BIGINT
)

Вставьте конкретное значение:

INSERT INTO good_times VALUES (
    UNIX_TIMESTAMP(CONVERT_TZ("2014-12-03 12:24:54", '+00:00', @@global.time_zone))
);

Или, конечно, это намного лучше из вашего приложения, например:

$statement = $myDB->prepare('INSERT INTO good_times VALUES (?)');
$statement->execute([$someTime->getTimestamp()]);

Выбирать:

SELECT a_time FROM good_times;

Существуют методы фильтрации относительного времени (выберите сообщения за последние 30 дней, найдите пользователей, которые купили в течение 10 минут после регистрации), выходящие за рамки здесь.

Ваше мнение о том, что DATETIME не имеет значения, если не понят часовой пояс, не нарушает его. Код вашего приложения должен преобразовать значение datetime в желаемый часовой пояс, прежде чем вставлять его в базу данных, поэтому при извлечении значения из базы данных вы будете знать, в каком часовом поясе оно находится. Даже в этом нет необходимости, если ваше приложение не заботится о часовой пояс, что может иметь место, когда все пользователи приложения находятся в одном часовом поясе (например, приложение используется только во Франции).

Marko 14.08.2020 01:59

@Marko этот аргумент одинаково хорошо применим для хранения значений datetime в базе данных, как и VARCHAR: код вашего приложения должен преобразовать значение в желаемый формат, прежде чем оно будет вставлено в базу данных. Я считаю, что базы данных созданы для хранения данных, включая весь контекст, необходимый для того, чтобы эти данные имели значение.

William Entriken 24.08.2020 19:38

нет, он не применяется одинаково хорошо, потому что вы не можете манипулировать значениями VARCHAR с помощью встроенных в базу данных функций даты и операторов сравнения дат.

Marko 25.08.2020 17:20

Вот встроенная функция MySQL, применяемая к значению ISO 8601 VARCHAR: SELECT DATE_ADD("2020-01-01", INTERVAL 2 DAY). Вот встроенный в MySQL оператор сравнения дат, применяющий ISO 8601 VARCHARs: SELECT "2020-01-01" < "2020-03-01"

William Entriken 02.09.2020 21:26

Он работает со строкой ISO 8601, потому что MySQL распознает ее как литерал даты и неявно приводит значение VARCHAR к DATE. Разница в том, что сохранение значения в столбце VARCHAR займет 10 байтов, тогда как сохранение его в столбце DATE займет 3 байта. Я также считаю, что значение VARCHAR будет неявно приводиться КАЖДЫЙ РАЗ, когда вы используете его со встроенной функцией даты или операторами сравнения дат, что далеко не эффективно. Типы DATE и DATETIME реализованы не просто так. Кроме того, начиная с MySQL 8.0.19 t можно указать смещение часового пояса с помощью DATETIME.

Marko 02.09.2020 23:04

чтобы исправить себя, строка VARCHAR ISO 8601 займет 11 байт данных, а не 10.

Marko 02.09.2020 23:12

① Вы согласились, что использование DATETIME и VARCHAR одинаково эффективно. ② Вы поднимаете новый вопрос, что VARCHAR использует больше памяти, чем DATE, с чем, конечно, я согласен. Теперь это вопрос предпочтения, предпочтет ли разработчик данных расточительный подход (VARCHAR) или небезопасный (DATETIME). ③ Напоследок вы упомянули версию 8.0.19. Спасибо, это актуальная информация, которую я добавил к ответу, с честью.

William Entriken 06.09.2020 19:36

По вашей логике, мы могли бы хранить числа как VARCHAR, это прекрасно работает в MySQL, но это все еще плохой дизайн. Они могут быть одинаково эффективными, но не столь же эффективными с точки зрения хранения И скорости выполнения. DATETIME был создан по какой-то причине, не знаю, почему вы пытаетесь это оспорить.

Marko 01.10.2020 20:43

Мы можем хранить что угодно как угодно. Но только BIGINT логически представляет нелокальное время. DATETIME был разработан для поддержки определения SQL 1960-х годов (doi: 10.1145 / 362384.362685). В то время никто не думал о часовых поясах, и с тех пор MySQL немного улучшил эту тему.

William Entriken 07.03.2021 18:19

Я не понимаю, насколько уместен ваш последний комментарий. Ваша исходная точка зрения заключалась в том, что DATETIME не нужен, потому что мы могли бы просто хранить данные как VARCHAR. Как я уже сказал, с помощью этой логики мы могли бы также хранить числа как VARCHAR, но мы этого не делаем, потому что наличие выделенного типа данных с оптимизированными для него операциями делает выполнение намного быстрее и использует меньше памяти.

Marko 07.03.2021 19:03

DATETIME vs TIMESTAMP:

TIMESTAMP используется для отслеживания изменений записей и обновления каждый раз, когда запись изменяется.

DATETIME используется для хранения определенного и статического значения, на которое не влияют никакие изменения в записях.

TIMESTAMP также зависит от других настроек, связанных с ЧАСОВЫМ ПОЯСОМ. DATETIME постоянно.

TIMESTAMP внутренне преобразовал текущий часовой пояс в UTC для хранения, а во время извлечения преобразовал обратно в текущий часовой пояс.

DATETIME не может этого сделать.

TIMESTAMP составляет 4 байта, а DATETIME - 8 байтов.

Поддерживаемый диапазон TIMESTAMP: «1970-01-01 00:00:01» UTC по «2038-01-19 03:14:07» UTC. Поддерживаемый диапазон DATETIME: С «1000-01-01 00:00:00» по «9999-12-31 23:59:59»

Другие вопросы по теме