Search code examples
phpdatemktime

mktime forcing date to December 1969


I am having an interesting problem with the mktime function. I looked at the solutions offered on here prior and none seemed to be resolved or helped (strotime doesn't change the results I see).

I have a monthly report that I am trying to make as error-proof as possible for my users, so I'm only requesting a month and a year. I will provide the best day for the report in the code.

My form has a drop-down selection for the months, and the values for the month are two-digit integers (01, 02, etc). The year is four-digit, filled out manually by the user.

Every works great up until the year 2038... I know, I know, it's a long way off, but the project is supposed to have a 20-year scope and so in the last two years, I'm running into issues.

here's how I'm receiving the information from the form:

$month = filter_var($_POST["month"], FILTER_SANITIZE_NUMBER_INT);
$year = filter_var($_POST["year"], FILTER_SANITIZE_NUMBER_INT);

Then, I use mktime to combine the month and year with my day (27th): $timeStamp = mktime(0,0,0,$month,27,$year);

Then I assign it to a variable in a date form that MySQL likes: $reportdate = date('Y-m-j',$timeStamp);

I've echoed out the results of $month and $year and they are coming across correctly, but when I echo out $reportdate, it always says 12/31/1969.

03
2038
1969-12-31

It doesn't matter what month I choose. December 2037 reports perfectly, anything beyond that fails.

Is this something that is fixable or am I just going to have to say that's the way the cookie crumbles...?


Solution

  • This is because your timestamp is overflowing, and is caused by the year 2038 problem.

    Basically, integers are represented as signed 32-bits numbers, which can hold a maximum value of 2147483648. So, in a UNIX timestamp, that is a certain amount in seconds, which is about 68 years.

    In fact, Google tells me:

    (2^31) * seconds = 68.0511039 years
    

    So, UNIX timestamp is time since the UNIX epoch, Jan 1st 1970 00:00:00 UTC, meaning the largest date that can be represented in a 32-bit UNIX timestamp would have a year of:

    1970 + ~68 = ~2038.
    

    If you need to support these dates, use the DateTime class, as it does not have such a restriction, like so:

    $date = new DateTime( "now", new DateTimeZone( 'America/New_York'));
    $date->setDate( $year, $month, 27);
    // $date->setTime( 0, 0, 0);
    echo $date->format('Y-m-j');