3

select unix_timestamp('2038-01-19') returns 2147472000

while select unix_timestamp('2038-01-20') returns 0

I have checked out the year 2038 problem.

My linux OS is 64 bit and installed mysql version is also 64 bits. What is the solution to this problem now?

mysql --version returns mysql Ver 14.14 Distrib 5.5.47, for Linux (x86_64) using readline 5.1
Php is 64 bit too.

Tried BigInt too, didn't work (returns the same thing).

Danyal Sandeelo
  • 12,196
  • 10
  • 47
  • 78

2 Answers2

6

Simply put, for MySQL, store dates as DATETIME rather than TIMESTAMP.

TIMESTAMP is 4 bytes, so there is no physical room to store more seconds than since 1970-1-1 to 2038-01-19...

DATETIME, instead, has a range of 1000-1-1 to 9999-12-31...

See also this complete question/answer: PHP & mySQL: Year 2038 Bug: What is it? How to solve it?

UPDATE: One possible alternative I see, if you CAN'T change your fields types, is to interpet your timestamps differently...
I mean: if the first event your application will keep track of is - say - 2000-1-1, you could implement a filter on backend (or in a stored procedure inside the database), to add (2000-1-1 - 1970-1-1) seconds to your timestamps when reading, and subtract the same amount when reading... This should give you 30 more years of 'survival'...

Community
  • 1
  • 1
MarcoS
  • 17,323
  • 24
  • 96
  • 174
4

MySQL documentation is in general extremely vague about the data types returned by functions and UNIX_TIMESTAMP() is not an exception. Unless we check the source code I think we can only make an educated guess.

At Date and Time Type Overview we can read that the TIMESTAMP data type itself has a documented range that doesn't depend on the server architecture:

The range is '1970-01-01 00:00:01.000000' UTC to '2038-01-19 03:14:07.999999' UTC. TIMESTAMP values are stored as the number of seconds since the epoch ('1970-01-01 00:00:00' UTC). A TIMESTAMP cannot represent the value '1970-01-01 00:00:00' because that is equivalent to 0 seconds from the epoch and the value 0 is reserved for representing '0000-00-00 00:00:00', the “zero” TIMESTAMP value.

Even if we make sure we pass a proper date type:

mysql> select
    ->  str_to_date('2038-01-20', '%Y-%m-%d'),
    ->  unix_timestamp(str_to_date('2038-01-20', '%Y-%m-%d'));
+---------------------------------------+-------------------------------------------------------+
| str_to_date('2038-01-20', '%Y-%m-%d') | unix_timestamp(str_to_date('2038-01-20', '%Y-%m-%d')) |
+---------------------------------------+-------------------------------------------------------+
| 2038-01-20                            |                                                     0 |
+---------------------------------------+-------------------------------------------------------+
1 row in set (0.01 sec)

... we still get 0, the silly function flag for errors:

If you pass an out-of-range date to UNIX_TIMESTAMP(), it returns 0.

So it's kind of safe to assume that UNIX_TIMESTAMP() returns a value of TIMESTAMP type thus 2038+ is not supported.

In short: you'll have to calculate timestamps somewhere else (i.e., your client code). Since there's a PHP tag:

$t = new DateTime('2038-01-20', new DateTimeZone('UTC'));
var_dump( $t->format('U') );

string(10) "2147558400"


P.S. MariaDB, the MySQL fork, has the same restriction but it documents it better:

Timestamps in MariaDB have a maximum value of 2147483647, equivalent to 2038-01-19 05:14:07. This is due to the underlying 32-bit limitation. Using the function on a date beyond this will result in NULL being returned.

Álvaro González
  • 142,137
  • 41
  • 261
  • 360