Dates7 min readExamples run on PHP 8.5.10

mktime()

Learn how PHP 8.4 mktime() turns clock and calendar parts into a Unix timestamp, how it normalizes overflow values, and which mistakes to avoid.

Signature

mktime(
    int $hour,
    ?int $minute = null,
    ?int $second = null,
    ?int $month = null,
    ?int $day = null,
    ?int $year = null
): int|false

Purpose

mktime() builds a Unix timestamp from separate date and time parts. The timestamp counts seconds since the Unix Epoch, 1970-01-01 00:00:00 GMT. The parts are interpreted in the current default timezone, so the same arguments can give different timestamps under different timezone settings. Use gmmktime() when the parts are meant as GMT.

The function is handy when you have numbers such as an hour, a month and a day, for example from a form or a calendar grid, and need a single integer that date() can format.

Signature

Parameters and defaults

  • hour is required. Since PHP 8.0, calling mktime() with no arguments throws ArgumentCountError. Use time() when you want the current timestamp.
  • minute and second are the minute and second within the hour and minute.
  • month, day and year come last, in that unusual order: month, day, year.
  • Every optional argument that is omitted or null takes the current local value. A call such as mktime(0) therefore depends on the clock and is not repeatable. Pass every part when you need a deterministic result.
  • A year from 0 to 69 maps to 2000–2069, and 70 to 100 maps to 1970–2000. Prefer four-digit years.

Return value and failure

The function returns an integer timestamp. It returns false if the result does not fit in a PHP integer. In practice that is rare on 64-bit builds, but code that accepts arbitrary user input should still check for false before formatting the value.

Example 1: a basic timestamp

The timezone is set to UTC so the numbers are predictable.

Example
<?php
date_default_timezone_set('UTC');
$ts = mktime(14, 30, 15, 7, 4, 2024);
echo $ts, "\n";
echo date('Y-m-d H:i:s', $ts), "\n";
echo date('l', $ts), "\n";
Output
1720103415
2024-07-04 14:30:15
Thursday

The integer can be stored, compared or passed to date() for any display format.

Example 2: out-of-range values are normalized

Values outside the normal range roll over into the next or previous unit. Month 13 is January of the next year, and day 0 is the last day of the previous month. Large hour, minute and second values carry upward.

Example
<?php
date_default_timezone_set('UTC');
echo date('Y-m-d', mktime(0, 0, 0, 13, 1, 2024)), "\n";
echo date('Y-m-d', mktime(0, 0, 0, 12, 32, 2024)), "\n";
echo date('Y-m-d', mktime(0, 0, 0, 3, 0, 2024)), "\n";
echo date('Y-m-d H:i:s', mktime(25, 61, 61, 1, 1, 2024)), "\n";
Output
2025-01-01
2025-01-01
2024-02-29
2024-01-02 02:02:01

This behavior makes date arithmetic short, but it also means mktime() will never tell you that an input such as February 31 is invalid. It quietly converts it to a different date.

Example 3: date arithmetic and two-digit years

Example
<?php
date_default_timezone_set('UTC');

function addDays(int $month, int $day, int $year, int $days): string
{
    return date('Y-m-d', mktime(0, 0, 0, $month, $day + $days, $year));
}

$result = [
    'next' => addDays(2, 20, 2024, 15),
    'feb2023Days' => (int) date('t', mktime(0, 0, 0, 3, 0, 2023)),
    'year69' => date('Y', mktime(0, 0, 0, 1, 1, 69)),
    'year70' => date('Y', mktime(0, 0, 0, 1, 1, 70)),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"next":"2024-03-06","feb2023Days":28,"year69":"2069","year70":"1970"}

Adding days to the day argument lets PHP handle month lengths and leap years. Asking for day 0 of March gives the final day of February, which is a common way to find a month's length.

Edge cases

  • Daylight saving time: Building a date with mktime() is usually safer than adding a fixed number of seconds per day, because a local day is not always 86,400 seconds long. Times that are skipped or repeated at a clock change still need care.
  • Midnight: mktime(0, 0, 0, ...) gives local midnight at the start of that day, not a UTC timestamp, unless the default timezone is UTC.
  • Negative values: Negative hours, minutes, seconds, months and days count backward from the start of the relevant unit.
  • Range on 32-bit systems: Where time_t is a 32-bit signed integer, the usable years are roughly 1901 to 2038.

Common mistakes

  1. Writing the arguments in year, month, day order. The correct order is month, day, year.
  2. Leaving out trailing arguments and expecting zero. Omitted values mean the current local value.
  3. Treating mktime() as a validator. Use checkdate() first when an impossible date must be rejected.
  4. Forgetting the timezone. Set it explicitly, or use gmmktime() or DateTimeImmutable with a named zone.
  5. Using two-digit years and expecting the current century.
  6. Calling mktime() with no arguments. Use time() instead.
  • gmmktime() builds a timestamp from GMT parts.
  • checkdate() validates a Gregorian date.
  • date() formats a timestamp.
  • time() returns the current timestamp.
  • DateTimeImmutable offers an object-based API with explicit timezones.

Recap

mktime() converts hour, minute, second, month, day and year into an integer timestamp in the default timezone. Remember the month-day-year order, pass every part when you need a repeatable result, and rely on its normalization for arithmetic. It does not validate dates, and it returns false only when the result cannot fit in an integer.

Tested examples

Basic timestamp in UTC
<?php
date_default_timezone_set('UTC');
$ts = mktime(14, 30, 15, 7, 4, 2024);
echo $ts, "\n";
echo date('Y-m-d H:i:s', $ts), "\n";
echo date('l', $ts), "\n";
Output
1720103415
2024-07-04 14:30:15
Thursday
Out-of-range values are normalized
<?php
date_default_timezone_set('UTC');
echo date('Y-m-d', mktime(0, 0, 0, 13, 1, 2024)), "\n";
echo date('Y-m-d', mktime(0, 0, 0, 12, 32, 2024)), "\n";
echo date('Y-m-d', mktime(0, 0, 0, 3, 0, 2024)), "\n";
echo date('Y-m-d H:i:s', mktime(25, 61, 61, 1, 1, 2024)), "\n";
Output
2025-01-01
2025-01-01
2024-02-29
2024-01-02 02:02:01
Date arithmetic and two-digit years
<?php
date_default_timezone_set('UTC');

function addDays(int $month, int $day, int $year, int $days): string
{
    return date('Y-m-d', mktime(0, 0, 0, $month, $day + $days, $year));
}

$result = [
    'next' => addDays(2, 20, 2024, 15),
    'feb2023Days' => (int) date('t', mktime(0, 0, 0, 3, 0, 2023)),
    'year69' => date('Y', mktime(0, 0, 0, 1, 1, 69)),
    'year70' => date('Y', mktime(0, 0, 0, 1, 1, 70)),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"next":"2024-03-06","feb2023Days":28,"year69":"2069","year70":"1970"}