34

我有数千个日期,格式如下:

2011-10-02T23:25:42Z(在 UTC 中也称为 ISO 8601)

我应该使用什么 MySQL 数据类型在 MySQL 数据库中存储这样的 ISO8601 日期?例如Datetimetimestamp还是别的什么?

哪个最适合比较(例如,获取两个日期/时间之间的记录)并对查询结果进行排序?如果数据库很大怎么办?

将上述 PHP 字符串转换为 MySQL 存储的最佳方法是什么?(我猜date_default_timezone_set('UTC');会被使用?)

4

6 回答 6

19

我认为将日期时间值保存在类型字段中DATETIME是一种自然的方式。

根据我自己对当前 PHP 应用程序的经验,只有read/write与此信息相关的操作可能会出现问题。

DATETIME正确执行整个过程的一种可能的解决方案(假设您使用数据类型)可能是以下方法:

读取 PHP 使用的 DATETIME 值

  1. 从数据库中获取DATETIME字段,将查询中的字段转换为字符串表示形式,方法'2011-10-02T23:25:42Z'是使用带有格式化字符串的DATE_FORMATMySQL 函数( DATE_FORMAT 上的文档'%Y-%m-%dT%H:%i:%sZ'
  2. 以这种特定格式读取获取的列值,并在 PHP 中将其从字符串转换为对 PHP 有效的真实日期时间表示(例如给定格式化字符串的DateTime类对象和DateTime::createFromFormat静态方法(并转义以避免将它们视为格式化指令)(docs for方法)。'Y-m-d\TH:i:s\Z'TZ
  3. 将转换后的值用作具有所有适用逻辑的真实日期时间值,例如真实日期比较(不是文本比较)等。

将 PHP 日期时间写入 MySQL 数据库

  1. 使用类对象的方法,使用与格式化字符串(文档)之前相同的方法,将 PHPDateTime类对象转换为我们的 ISO 8601 UTC 格式字符串表示。DateTimeformat'Y-m-d\TH:i:s\Z'
  2. 使用这种准备好的字符串作为 MySQL 函数的参数(带有格式化字符串)对数据库信息执行INSERT/操作,该函数将其转换为真实的数据库值(STR_TO_DATE 上的文档)。UPDATESTR_TO_DATE'%Y-%m-%dT%H:%i:%sZ'DATETIME

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's 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 数据库之间操作日期时间值有很大帮助。

我希望它也会对您有所帮助。

于 2015-01-30T22:33:58.007 回答
13

您可以使用DateTime数据类型来存储日期和时间。

使用CAST函数将此类字符串转换为 mysqlDateTime类型。

这是一个例子:

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

这会给你2011-10-02 23:25:42

希望这会帮助你。

于 2015-01-30T19:27:49.523 回答
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 到 '2038-01-09 03:14:07' UTC 的范围
  • 受时区设置影响。
  • 4字节存储
  • 允许on update current_timestamp所有版本的列。
  • 索引更快
  • NULL不是可能的默认值
  • 值从当前时区转换UTC为存储,并从当前时区转换回UTC当前时区以进行检索。

约会时间

  • '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

并且,为了每天不断重复不使用已mysql* 弃用功能的 SO 回答者,请使用PDOmysqli*何时进行插入。

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

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

于 2015-02-03T01:24:02.213 回答
3

您不能以原始 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 对象时区设置为 UTC。

$datetime->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d H:i:s');
于 2015-02-05T09:42:04.297 回答
1

在我的 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

如果您的日期时间有小数微秒;在 Z 之前包括 .%f 如下:

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
于 2019-09-21T11:22:56.390 回答
0

以下是使用日期时间更好的原因。

  1. 使用 datetime 您将能够在 mysql 端进行日期操作 - 例如减去日、月
  2. 您将能够对数据进行排序。
  3. 如果数据库很大 - varchar 在 HDD 上占据更多位置
于 2011-11-08T08:21:45.563 回答