Documentation Home
MySQL 8.0 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 47.0Mb
PDF (A4) - 47.1Mb
PDF (RPM) - 42.4Mb
HTML Download (TGZ) - 10.8Mb
HTML Download (Zip) - 10.9Mb
HTML Download (RPM) - 9.4Mb
Man Pages (TGZ) - 227.0Kb
Man Pages (Zip) - 333.7Kb
Info (Gzip) - 4.2Mb
Info (Zip) - 4.2Mb
Excerpts from this Manual

MySQL 8.0 Reference Manual  /  ...  /  The DATE, DATETIME, and TIMESTAMP Types

11.3.1 The DATE, DATETIME, and TIMESTAMP Types

The DATE, DATETIME, and TIMESTAMP types are related. This section describes their characteristics, how they are similar, and how they differ. MySQL recognizes DATE, DATETIME, and TIMESTAMP values in several formats, described in Section 9.1.3, “Date and Time Literals”. For the DATE and DATETIME range descriptions, supported means that although earlier values might work, there is no guarantee.

The DATE type is used for values with a date part but no time part. MySQL retrieves and displays DATE values in 'YYYY-MM-DD' format. The supported range is '1000-01-01' to '9999-12-31'.

The DATETIME type is used for values that contain both date and time parts. 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 is used for values that contain both date and time parts. TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC.

A DATETIME or TIMESTAMP value can include a trailing fractional seconds part in up to microseconds (6 digits) precision. In particular, any fractional part in a value inserted into a DATETIME or TIMESTAMP column is stored rather than discarded. With the fractional part included, the format for these values is 'YYYY-MM-DD hh:mm:ss[.fraction]', the range for DATETIME values is '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999', and the range for TIMESTAMP values is '1970-01-01 00:00:01.000000' to '2038-01-19 03:14:07.999999'. The fractional part should always be separated from the rest of the time by a decimal point; no other fractional seconds delimiter is recognized. For information about fractional seconds support in MySQL, see Section 11.3.5, “Fractional Seconds in Time Values”.

The TIMESTAMP and DATETIME data types offer automatic initialization and updating to the current date and time. For more information, see Section 11.3.4, “Automatic Initialization and Updating for TIMESTAMP and DATETIME”.

MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME.) By default, the current time zone for each connection is the server's time. The time zone can be set on a per-connection basis. As long as the time zone setting remains constant, you get back the same value you store. If you store a TIMESTAMP value, and then change the time zone and retrieve the value, the retrieved value is different from the value you stored. This occurs because the same time zone was not used for conversion in both directions. The current time zone is available as the value of the time_zone system variable. For more information, see Section 5.1.13, “MySQL Server Time Zone Support”.

Invalid DATE, DATETIME, or TIMESTAMP values are converted to the zero value of the appropriate type ('0000-00-00' or '0000-00-00 00:00:00'), if the SQL mode permits this conversion. The precise behavior depends on which if any of strict SQL mode and the NO_ZERO_DATE SQL mode are enabled; see Section 5.1.11, “Server SQL Modes”.

Be aware of certain properties of date value interpretation in MySQL:

  • MySQL permits a relaxed format for values specified as strings, in which any punctuation character may be used as the delimiter between date parts or time parts. In some cases, this syntax can be deceiving. For example, a value such as '10:11:12' might look like a time value because of the :, but is interpreted as the year '2010-11-12' if used in a date context. The value '10:45:15' is converted to '0000-00-00' because '45' is not a valid month.

    The only delimiter recognized between a date and time part and a fractional seconds part is the decimal point.

  • The server requires that month and day values be valid, and not merely in the range 1 to 12 and 1 to 31, respectively. With strict mode disabled, invalid dates such as '2004-04-31' are converted to '0000-00-00' and a warning is generated. With strict mode enabled, invalid dates generate an error. To permit such dates, enable ALLOW_INVALID_DATES. See Section 5.1.11, “Server SQL Modes”, for more information.

  • MySQL does not accept TIMESTAMP values that include a zero in the day or month column or values that are not a valid date. The sole exception to this rule is the special zero value '0000-00-00 00:00:00', if the SQL mode permits this value. The precise behavior depends on which if any of strict SQL mode and the NO_ZERO_DATE SQL mode are enabled; see Section 5.1.11, “Server SQL Modes”.

  • Dates containing 2-digit year values are ambiguous because the century is unknown. MySQL interprets 2-digit year values using these rules:

    • Year values in the range 00-69 are converted to 2000-2069.

    • Year values in the range 70-99 are converted to 1970-1999.

    See also Section 11.3.7, “2-Digit Years in Dates”.

User Comments
User comments in this section are, as the name implies, provided by MySQL users. The MySQL documentation team is not responsible for, nor do they endorse, any of the information provided here.
  Posted by Dean Trower on November 23, 2018
When using the TIMESTAMP type in timezone settings with daylight savings, you must be aware that:

* Storing data in the column will be ambiguous at the end of daylight savings, because the local-time hour gets repeated twice.

* At the start of daylight savings, when clocks are turned forwards, there's a "missing hour". Technically times in this hour aren't valid, but if you do try to store a time from this missing hour in a TIMESTAMP column and then read it back, you WON'T get out what you put in! (Contrary to what the page states).

* If you ORDER BY your timezone column, it will order by the internal UTC representation; *displayed* times can therefore be out of order when daylight savings ends.

* HOWEVER, any computation will use the derived local time, even in the ORDER BY clause, so if ts is a TIMESTAMP column, "ORDER BY ts" "ORDER BY <column number>", or "ORDER BY UNIX_TIMESTAMP(ts)" give UTC-time ordering, but "ORDER BY ts+0", "ORDER BY ts + INTERVAL 1 SECOND", "ORDER BY CAST(ts AS datetime)" will be ordered by *local* time, which may result in a different row ordering!

* Similarly, comparisons between timestamp values, i.e. ts1<ts2 etc are always carried out using local-time values. So the result of this comparison can CHANGE depending on the timezone you set, if the values are on different sides of the turn-the-clocks-back point: IT IS NOT A COMPARISON BETWEEN UTC TIMESTAMPS!!! To do that, compare UNIX_TIMESTAMP(ts1)<UNIX_TIMESTAMP(ts2)

These problems can be obviated by setting the server timezone to UTC (temporarily, if you prefer), i.e.:

SET @oldTZ := @@time_zone; SET @@time_zone := '+00:00';
# Do something with timestamps here; it'll work reliably[*] as everything is in UTC
SET @@time_zone := @oldTZ;

[*] Actually, not entirely true, as there may also occasionally be leap-seconds, represented by hh:59:59 repeating twice. So events with these timestamps may be more than one second apart, and there isn't a 1-1 correspondence between actual seconds and displayed seconds; and when storing decimal seconds (milliseconds, etc), once again all the local-times-are-out-of order issues can arise. See
  Posted by Dean Trower on November 23, 2018
It is important to note that if you have a table with a TIMESTAMP column:


and you insert a value like so:


The value will undergo a roundtrip conversion, from a number to a date, and then back again, before insertion!
Due to daylight savings time and/or leap-seconds, the inserted value may not be what you started with!


For example, in the Australian Eastern Daylight Time timezone, the result of the above query is 1522513800 rather than 1522510200, as the latter value falls within the hour that gets repeated at the end of daylight savings.

You can mitigate this problem by switching to a non-daylight-savings timezone (temporarily if you prefer), but I believe it also arises due to leap-seconds, which cannot be mitigated this way. i.e.

SET @oldTZ := @@time_zone;
SET @@time_zone := '+00:00';

# Do something with timestamps; they'll work reliably here unless you hit a leap-second

SET @@time_zone := @oldTZ;

I'm not aware of any way to insert a "raw" UNIX time-value into a TIMESTAMP column exactly, without conversion to a datetime and back again.
(Though bug report #83852 includes a feature request for exactly this, plus some helper functions).
  Posted by Dean Trower on November 23, 2018
It turns out there *IS* a method you can use to insert a "raw" timestamp value.
You can just do this:

SET @@timestamp := 1522510200;
SET @@timestamp := DEFAULT;

It's rather clumsy, though!

(See the documentation page for Server System Variables: