MySQL 8.4 参考手册  /  ...  /  日期和时间字面值

11.1.3 日期和时间字面值

日期和时间值可以使用多种格式表示,例如带引号的字符串或数字,具体取决于值的精确类型和其他因素。例如,在 MySQL 预期日期的上下文中,它会将 '2015-07-21'、'20150721' 和 20150721 解释为日期。

本节介绍日期和时间字面值的 akzeptable 格式。有关时间数据类型的更多信息,例如允许值的范围,请参见第 13.2 节“日期和时间数据类型”。

标准 SQL 和 ODBC 日期和时间字面值

标准 SQL 要求使用类型关键字和字符串指定时间字面值。关键字和字符串之间的空格是可选的。

DATE 'str'
TIME 'str'
TIMESTAMP 'str'

MySQL 识别但与标准 SQL 不同,它不需要类型关键字。要符合标准的应用程序应为时间字面值包含类型关键字。

MySQL 还识别与标准 SQL 语法相对应的 ODBC 语法

{ d 'str' }
{ t 'str' }
{ ts 'str' }

MySQL 使用类型关键字和 ODBC 结构分别生成 DATE、TIME 和 DATETIME 值,如果指定了尾随小数秒部分,则包括该部分。TIMESTAMP 语法在 MySQL 中生成 DATETIME 值,因为 DATETIME 的范围更接近于标准 SQL TIMESTAMP 类型,后者的年份范围为 0001 到 9999。(MySQL TIMESTAMP 年份范围为 1970 到 2038。)

日期和时间上下文中的字符串和数值字面值

MySQL 识别以下格式的 DATE 值

  • 作为 'YYYY-MM-DD' 或 'YY-MM-DD' 格式的字符串。允许使用“宽松”语法,但已弃用:任何标点符号都可以用作日期部分之间的分隔符。例如,'2012-12-31'、'2012/12/31'、'2012^12^31' 和 '2012@12@31' 是等效的。使用除破折号 (-) 以外的任何字符作为分隔符都会引发警告,如下所示

    mysql> SELECT DATE'2012@12@31';
    +------------------+
    | DATE'2012@12@31' |
    +------------------+
    | 2012-12-31       |
    +------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 4095
    Message: Delimiter '@' in position 4 in datetime value '2012@12@31' at row 1 is
    deprecated. Prefer the standard '-'. 
    1 row in set (0.00 sec)
  • 作为 'YYYYMMDD' 或 'YYMMDD' 格式的无分隔符字符串,前提是该字符串作为日期有意义。例如,'20070523' 和 '070523' 被解释为 '2007-05-23',但 '071332' 是非法的(它具有无意义的月份和日期部分)并变为 '0000-00-00'。

  • 作为 YYYYMMDD 或 YYMMDD 格式的数字,前提是该数字作为日期有意义。例如,19830905 和 830905 被解释为 '1983-09-05'。

MySQL 识别以下格式的 DATETIME 和 TIMESTAMP 值

  • 作为 'YYYY-MM-DD hh:mm:ss' 或 'YY-MM-DD hh:mm:ss' 格式的字符串。MySQL 在这里也允许使用“宽松”语法,尽管这已弃用:任何标点符号都可以用作日期部分或时间部分之间的分隔符。例如,'2012-12-31 11:30:45'、'2012^12^31 11+30+45'、'2012/12/31 11*30*45' 和 '2012@12@31 11^30^45' 是等效的。在这些值中使用任何字符作为分隔符,而不是日期部分的破折号 (-) 和时间部分的冒号 (:),都会引发警告,如下所示

    mysql> SELECT TIMESTAMP'2012^12^31 11*30*45';
    +--------------------------------+
    | TIMESTAMP'2012^12^31 11*30*45' |
    +--------------------------------+
    | 2012-12-31 11:30:45            |
    +--------------------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 4095
    Message: Delimiter '^' in position 4 in datetime value '2012^12^31 11*30*45' at
    row 1 is deprecated. Prefer the standard '-'. 
    1 row in set (0.00 sec)

    日期和时间部分与小数秒部分之间唯一识别的分隔符是小数点。

    日期和时间部分可以用 T 而不是空格分隔。例如,'2012-12-31 11:30:45' '2012-12-31T11:30:45' 是等效的。

    以前,MySQL 支持日期和时间值中的任意数量的前导和尾随空格字符,以及 DATETIME 和 TIMESTAMP 值的日期和时间部分之间的空格字符。在 MySQL 8.4 中,此行为已弃用,并且存在多余的空格字符会触发警告,如下所示

    mysql> SELECT TIMESTAMP'2012-12-31   11-30-45';
    +----------------------------------+
    | TIMESTAMP'2012-12-31   11-30-45' |
    +----------------------------------+
    | 2012-12-31 11:30:45              |
    +----------------------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 4096
    Message: Delimiter ' ' in position 11 in datetime value '2012-12-31   11-30-45'
    at row 1 is superfluous and is deprecated. Please remove. 
    1 row in set (0.00 sec)

    当使用空格字符以外的空格字符时,也会引发警告,如下所示

    mysql> SELECT TIMESTAMP'2021-06-06
        '> 11:15:25';
    +--------------------------------+
    | TIMESTAMP'2021-06-06
     11:15:25'                       |
    +--------------------------------+
    | 2021-06-06 11:15:25            |
    +--------------------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 4095
    Message: Delimiter '\n' in position 10 in datetime value '2021-06-06
    11:15:25' at row 1 is deprecated. Prefer the standard ' '.
    1 row in set (0.00 sec)

    每个时间值只引发一个此类警告,即使分隔符、空格或两者都可能存在多个问题,如下面的语句系列所示

    mysql> SELECT TIMESTAMP'2012!-12-31  11:30:45';
    +----------------------------------+
    | TIMESTAMP'2012!-12-31  11:30:45' |
    +----------------------------------+
    | 2012-12-31 11:30:45              |
    +----------------------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 4095
    Message: Delimiter '!' in position 4 in datetime value '2012!-12-31  11:30:45'
    at row 1 is deprecated. Prefer the standard '-'. 
    1 row in set (0.00 sec)
    
    mysql> SELECT TIMESTAMP'2012-12-31  11:30:45';
    +---------------------------------+
    | TIMESTAMP'2012-12-31  11:30:45' |
    +---------------------------------+
    | 2012-12-31 11:30:45             |
    +---------------------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> SHOW WARNINGS\G
    *************************** 1. row ***************************
      Level: Warning
       Code: 4096
    Message: Delimiter ' ' in position 11 in datetime value '2012-12-31  11:30:45'
    at row 1 is superfluous and is deprecated. Please remove. 
    1 row in set (0.00 sec)
    
    mysql> SELECT TIMESTAMP'2012-12-31 11:30:45';
    +--------------------------------+
    | TIMESTAMP'2012-12-31 11:30:45' |
    +--------------------------------+
    | 2012-12-31 11:30:45            |
    +--------------------------------+
    1 row in set (0.00 sec)
  • 作为 'YYYYMMDDhhmmss' 或 'YYMMDDhhmmss' 格式的无分隔符字符串,前提是该字符串作为日期有意义。例如,'20070523091528' 和 '070523091528' 被解释为 '2007-05-23 09:15:28',但 '071122129015' 是非法的(它具有无意义的分秒部分)并变为 '0000-00-00 00:00:00'。

  • 作为 YYYYMMDDhhmmss 或 YYMMDDhhmmss 格式的数字,前提是该数字作为日期有意义。例如,19830905132800 和 830905132800 被解释为 '1983-09-05 13:28:00'。

DATETIME 或 TIMESTAMP 值可以包含一个尾随小数秒部分,精度最高为微秒(6 位数字)。小数部分应始终用小数点与时间的其余部分分开;不识别其他小数秒分隔符。有关 MySQL 中小数秒支持的信息,请参见第 13.2.6 节“时间值中的小数秒”。

包含两位数年份值的日期不明确,因为世纪未知。MySQL 使用以下规则解释两位数年份值

  • 70-99 范围内的年份值变为 1970-1999。

  • 00-69 范围内的年份值变为 2000-2069。

另请参见第 13.2.9 节“日期中的两位数年份”。

对于指定为包含日期部分分隔符的字符串的值,对于小于 10 的月份或日期值,无需指定两位数字。'2015-6-9' 与 '2015-06-09' 相同。类似地,对于指定为包含时间部分分隔符的字符串的值,对于小于 10 的小时、分钟或秒值,无需指定两位数字。'2015-10-30 1:2:3' 与 '2015-10-30 01:02:03' 相同。

指定为数字的值的长度应为 6、8、12 或 14 位数字。如果数字的长度为 8 或 14 位数字,则假定其格式为 YYYYMMDD 或 YYYYMMDDhhmmss,并且年份由前 4 位数字给出。如果数字的长度为 6 或 12 位数字,则假定其格式为 YYMMDD 或 YYMMDDhhmmss,并且年份由前 2 位数字给出。长度不是这些长度之一的数字将被解释为好像用前导零填充到最接近的长度。

以非分隔字符串形式指定的值将根据其长度进行解释。对于 8 个或 14 个字符长的字符串,年份由前 4 个字符表示。否则,年份由前 2 个字符表示。字符串将从左到右进行解释,以查找年、月、日、小时、分钟和秒的值,具体取决于字符串中存在的部件数量。这意味着您不应使用少于 6 个字符的字符串。例如,如果您指定 '9903',以为它表示 1999 年 3 月,MySQL 会将其转换为 “零” 日期值。这是因为年份和月份值分别是 99 和 03,但日期部分完全缺失。但是,您可以明确指定值为零来表示缺少的月份或日期部分。例如,要插入值 '1999-03-00',请使用 '990300'。

MySQL 识别以下格式的 TIME 值

  • 以 'D hh:mm:ss' 格式的字符串形式。您还可以使用以下““宽松””语法之一:'hh:mm:ss'、'hh:mm'、'D hh:mm'、'D hh' 或 'ss'。其中,D 表示天数,其值可以是 0 到 34。

  • 以 'hhmmss' 格式的不带分隔符的字符串形式,前提是它在时间上说得通。例如,'101112' 被理解为 '10:11:12',但 '109712' 非法(它的分钟部分无意义),会变成 '00:00:00'。

  • 以 hhmmss 格式的数字形式,前提是它在时间上说得通。例如,101112 被理解为 '10:11:12'。以下替代格式也可以理解:ss、mmss 或 hhmmss。

在 'D hh:mm:ss.fraction'、'hh:mm:ss.fraction'、'hhmmss.fraction' 和 hhmmss.fraction 时间格式中,可以识别尾随的小数秒部分,其中 fraction 是小数部分,精度最高为微秒(6 位数字)。小数部分应始终使用小数点与时间的其余部分分隔;不识别任何其他小数秒分隔符。有关 MySQL 中小数秒支持的信息,请参见 第 13.2.6 节,“时间值中的小数秒”。

对于以字符串形式指定的包含时间部分分隔符的 TIME 值,不需要为小于 10 的小时、分钟或秒值指定两位数字。'8:3:2' 与 '08:03:02' 相同。

将 TIMESTAMP 和 DATETIME 值插入表中时,您可以指定时区偏移量。偏移量附加到日期时间文字的时间部分,中间没有空格,并使用与设置 time_zone 系统变量相同的格式,但有以下例外

  • 对于小于 10 的小时值,需要一个前导零。

  • 值 '-00:00' 将被拒绝。

  • 不能使用 'EET' 和 'Asia/Shanghai' 等时区名称;在这种情况下也不能使用 'SYSTEM'。

插入的值的月份部分、日期部分或这两个部分都不能为零。无论服务器 SQL 模式设置如何,都会强制执行此操作。

此示例说明了使用不同的 time_zone 设置将带有时区偏移量的日期时间值插入 TIMESTAMP 和 DATETIME 列,然后检索它们

mysql> CREATE TABLE ts (
    ->     id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     col TIMESTAMP NOT NULL
    -> ) AUTO_INCREMENT = 1;

mysql> CREATE TABLE dt (
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     col DATETIME NOT NULL
    -> ) AUTO_INCREMENT = 1;

mysql> SET @@time_zone = 'SYSTEM';

mysql> INSERT INTO ts (col) VALUES ('2020-01-01 10:10:10'),
    ->     ('2020-01-01 10:10:10+05:30'), ('2020-01-01 10:10:10-08:00');

mysql> SET @@time_zone = '+00:00';

mysql> INSERT INTO ts (col) VALUES ('2020-01-01 10:10:10'),
    ->     ('2020-01-01 10:10:10+05:30'), ('2020-01-01 10:10:10-08:00');

mysql> SET @@time_zone = 'SYSTEM';

mysql> INSERT INTO dt (col) VALUES ('2020-01-01 10:10:10'),
    ->     ('2020-01-01 10:10:10+05:30'), ('2020-01-01 10:10:10-08:00');

mysql> SET @@time_zone = '+00:00';

mysql> INSERT INTO dt (col) VALUES ('2020-01-01 10:10:10'),
    ->     ('2020-01-01 10:10:10+05:30'), ('2020-01-01 10:10:10-08:00');

mysql> SET @@time_zone = 'SYSTEM';

mysql> SELECT @@system_time_zone;
+--------------------+
| @@system_time_zone |
+--------------------+
| EST                |
+--------------------+

mysql> SELECT col, UNIX_TIMESTAMP(col) FROM dt ORDER BY id;
+---------------------+---------------------+
| col                 | UNIX_TIMESTAMP(col) |
+---------------------+---------------------+
| 2020-01-01 10:10:10 |          1577891410 |
| 2019-12-31 23:40:10 |          1577853610 |
| 2020-01-01 13:10:10 |          1577902210 |
| 2020-01-01 10:10:10 |          1577891410 |
| 2020-01-01 04:40:10 |          1577871610 |
| 2020-01-01 18:10:10 |          1577920210 |
+---------------------+---------------------+

mysql> SELECT col, UNIX_TIMESTAMP(col) FROM ts ORDER BY id;
+---------------------+---------------------+
| col                 | UNIX_TIMESTAMP(col) |
+---------------------+---------------------+
| 2020-01-01 10:10:10 |          1577891410 |
| 2019-12-31 23:40:10 |          1577853610 |
| 2020-01-01 13:10:10 |          1577902210 |
| 2020-01-01 05:10:10 |          1577873410 |
| 2019-12-31 23:40:10 |          1577853610 |
| 2020-01-01 13:10:10 |          1577902210 |
+---------------------+---------------------+

选择日期时间值时,不会显示偏移量,即使插入时使用了偏移量也是如此。

支持的偏移值范围为 -13:59 到 +14:00(含)。

预处理语句接受包含时区偏移量的日期时间文字作为参数值。