Подтвердить что ты не робот

Как сохранить дату UTC ISO8601 в базе данных MySQL?

У меня есть тысячи дат в следующем формате:

2011-10-02T23:25:42Z (также известный как ISO 8601 в UTC)

Какой тип данных MySQL следует использовать для хранения такой даты ISO8601 в базе данных MySQL? Например. Datetime, timestamp или что-то еще?

Что лучше для сравнения (например, получение записей между двумя датами/временем) и упорядочение результатов запросов? Что, если база данных очень велика?

И какой будет лучший способ конвертировать приведенную выше строку PHP для хранения MySQL? (Я предполагаю, что date_default_timezone_set('UTC'); будет использоваться?)

4b9b3361

Ответ 1

Я думаю, что сохранение ваших значений даты в поле типа DATETIME было бы естественным способом.

Из моего собственного опыта работы с моим текущим PHP-приложением только операции read/write, касающиеся этой информации, могут быть проблематичными.

Одним из возможных решений (при условии, что вы используете тип данных DATETIME) для правильного выполнения всего процесса может быть следующий подход:

Чтение значений DATETIME для использования PHP

  • Получите DATETIME поля из вашей базы данных, преобразуя их в запрос в строковое представление в форме '2011-10-02T23:25:42Z' с помощью DATE_FORMAT функции MySQL с строкой форматирования '%Y-%m-%dT%H:%i:%sZ' (docs на DATE_FORMAT)
  • Прочитать полученное значение столбца в этом конкретном формате и преобразовать его в PHP из строки в реальное представление даты-времени, действительное для PHP (например, объекты класса DATETIME и DateTime::createFromFormat статический метод с заданной строкой форматирования 'Y-m-d\TH:i:s\Z' ( и Z, чтобы избежать обработки их как директив форматирования) (docs для метода).
  • Использовать преобразованные значения в качестве реальных значений даты и времени со всеми применимыми логическими параметрами, такими как сопоставление реальной даты (не сравнение текста) и т.д.

Написание PHP date-time для базы данных MySQL

  • Преобразовать объект класса PHP DATETIME в наш ISO 8601 в строчном представлении формата UTC с использованием метода DATETIME class object format с тем же значением, что и перед строкой форматирования 'Y-m-d\TH:i:s\Z' (документация).
  • Выполните операцию INSERT/UPDATE по информации базы данных с использованием такой подготовленной строки в качестве параметра для функции MySQL STR_TO_DATE (с строкой форматирования '%Y-%m-%dT%H:%i:%sZ'), которая преобразует ее в реальную базу данных DATETIME value (docs на STR_TO_DATE).

Пример кода в PHP

Ниже приведен пример примера такого подхода с использованием объектов PDO:

$db = new PDO('mysql:host=localhost;dbname=my_db;charset=utf8', 'username', 'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    // run the query aquring 1 example row with DATETIME data 
    // converted with MySQL DATE_FORMAT function to its string representation 
    // in the chosen format (in our case: ISO 8601 / UTC)
    $stmt = $db->query("SELECT DATE_FORMAT(dt_column, '%Y-%m-%dT%H:%i:%sZ') AS formatted_dt_col"
                        ." FROM your_table LIMIT 1"); 

    if($stmt !== FALSE) {
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        // convert the acquired string representation from DB 
        // (i.e. '2011-10-02T23:25:42Z' )
        // to PHP DateTime object which has all the logic of date-time manipulation:    
        $dateTimeObject = DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $row['formatted_dt_col']);

        // the following should print i.e. 2011-10-02T23:25:42Z
        echo $dateTimeObject->format('Y-m-d\TH:i:s\Z');  

        // now let write PHP DateTime class object '$dateTimeObject' 
        // back to the database
        $stmtInsertDT = $db->prepare("INSERT INTO your_table(dt_column) " 
                             . " VALUES ( STR_TO_DATE(:par_formatted_dt_column, '%Y-%m-%dT%H:%i:%sZ') )");

        $dtAsTextForInsert = $dateTimeObject->format('Y-m-d\TH:i:s\Z');

        // convert '$dateTimeObject' to its ISO 8601 / UTC text represantation
        // in order to be able to put in in the query using PDO text parameter
        $stmtInsertDT->bindParam(':par_formatted_dt_column', $dtAsTextForInsert, PDO::PARAM_STR);

        $stmtInsertDT->execute();

        // So the real insert query being perform would be i.e.:
        /*
           INSERT INTO your_table(dt_column) 
           VALUES ( STR_TO_DATE('2011-10-02T23:25:42Z', '%Y-%m-%dT%H:%i:%sZ') )
        */
    }
}
catch(\PDOException $pexc) {
 // serve PDOException
}
catch(\Exception $exc) {
// in case of no-PDOException, serve general exception
}

Этот подход очень помог мне в операционных значениях времени между базами данных PHP и MySQL.

Я надеюсь, что это может оказаться полезным и для вас.

Ответ 2

Вы можете использовать тип данных DateTime для хранения даты и времени.

Используйте функцию CAST, чтобы вывести такие строки в тип mysql DateTime.

Вот пример:

CAST("2011-10-02T23:25:42Z" AS DATETIME)

Это даст вам 2011-10-02 23:25:42.

Надеюсь, это поможет вам.

Ответ 3

Вы можете легко преобразовать дату с помощью функции strtotime php:

date_default_timezone_set('UTC');
$date = '2011-10-02T23:25:42Z';//(aka ISO 8601 in UTC)
$time = strtotime($date); //time is now equals to the timestamp
$converted = date('l, F jS Y \a\t g:ia', $time); //convert to date if you prefer, credit to Marc B for the parameters

Теперь вы просто вставляете свою дату в MySQL с помощью timestamp или datetime в зависимости от того, какой из них наиболее подходит вашим потребностям. Здесь самые важные вещи, которые вы должны знать обо всех типах.


Отметка

  • Диапазон '1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' UTC
  • Затронуто настройкой часового пояса.
  • 4 байта хранения
  • разрешить on update current_timestamp для столбцов для всех версий.
  • Индекс быстрее.
  • NULL не является возможным значением по умолчанию
  • Значения преобразуются из текущего часового пояса в UTC для хранения и преобразуются обратно из UTC в текущую временную зону для извлечения.

Datetime

  • Диапазон "1000-01-01 00:00:00" до "9999-12-31 23:59:59"
  • Константа (временная зона не влияет)
  • 8-байтовая память
  • разрешить обновление по столбцам только с версии 5.6.5

Что лучше для сравнения (например, получение записей между двумя даты/времени) и упорядочивание результатов запросов? Как насчет того, база данных очень большая?

В соответствии с предыдущими пунктами, которые я изложил, вы должны использовать timestamp для очень большой базы данных, поскольку хранилище меньше, а индекс быстрее, что даст вам лучшую производительность для сравнения. Тем не менее, вы ДОЛЖНЫ БЫТЬ УВЕРЕНЫ, ваша дата будет соответствовать ограничениям timestamp, о которых я упоминал ранее, иначе у вас нет выбора и вы должны использовать datetime.

Документация для strtotime: http://php.net/manual/en/function.strtotime.php

И, пожалуйста, ради SO-ответчика, которые каждый день повторяют, чтобы не использовать функции mysql* DEPRECATED, используйте PDO или mysqli*, когда будете делать свои вставки.

http://php.net/manual/en/book.pdo.php

http://php.net/manual/en/book.mysqli.php

Ответ 4

Вы не можете сохранить дату в необработанном формате UTC ISO8601 (с представлением 2011-10-02T23:25:42Z) и сохранить все функциональные возможности SQL DATETIME.

Но вы должны знать, что MySQL (относительно http://dev.mysql.com/doc/refman/5.5/en/datetime.html) всегда сохраняет время/дату в UTC. Также вы можете изменить часовой пояс для своего соединения http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html

Итак, если вы выполняете в PHP

date_default_timezone_set('UTC');

и в MySQL

SET time_zone = +00:00

уверен, что PHP и MySQL будут использовать UTC.

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

Чтобы преобразовать любой PHP DateTime (без учета внутреннего часового пояса) в строку MySQL datetime, вы должны установить часовой пояс объекта DateTime в UTC.

$datetime->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s');

Ответ 5

Используя вашу дату и время в моей системе, которая называется PDT:

SELECT CONVERT_TZ(str_to_date('2011-10-02T23:25:42Z','%Y-%m-%dT%H:%i:%sZ'),'+00:00','SYSTEM') from dual;

2011-10-02 16:25:42

Если ваша дата и время имеют дробную микросекунду; включите.% f перед Z следующим образом:

SELECT CONVERT_TZ(str_to_date('2011-10-02T23:25:42.123456Z','%Y-%m-%dT%H:%i:%s.%fZ'),'+00:00','SYSTEM') from dual;

2011-10-02 16:25:42.123456

Ответ 6

Вот то, почему лучше использовать datetime.

  • С datetime вы сможете делать манипуляции с датами на стороне mysql - например, вычитать день, месяц
  • Вы сможете сортировать данные.
  • Если DB огромна - varchar занимает больше места на жестком диске