Dates7 min readExamples run on PHP 8.5.10

idate()

Learn how PHP idate() returns one date or time part as an integer, with its signature, failure cases, deterministic examples and common mistakes.

Signature

idate(string $format, ?int $timestamp = null): int|false

Purpose

idate() extracts a single piece of a date or time and gives it back as an integer. Where date() builds a formatted string, idate() answers one numeric question: what is the year, the month, the ISO week, the number of days in this month, or whether this is a leap year? Because the result is already an int, you can compare it, add to it or use it as an array index without casting.

Signature

Parameters and defaults

  • $format is a string that must hold exactly one format character. Unlike date(), you cannot combine characters or add separators. Characters in the supported set include Y (four-digit year), y (year, one or two digits), m (month number), d (day of the month), H (24-hour hour), h (12-hour hour), i (minutes), s (seconds), t (days in the month), L (1 for a leap year, otherwise 0), z (day of the year, counting from 0), w (day of the week, 0 for Sunday), N (ISO-8601 weekday, 1 for Monday through 7 for Sunday), W (ISO-8601 week number), o (ISO-8601 year), I (1 when daylight saving time is active), B (Swatch beat), U (Unix timestamp) and Z (time zone offset in seconds).
  • $timestamp is an optional Unix timestamp. If you omit it or pass null, PHP uses the current time, as time() would. Passing null has been allowed since PHP 8.0.

The parts are interpreted in the default time zone, so the same timestamp can give different hours or days under different zones. Always set the zone explicitly when you need repeatable results.

Return value and failure cases

On success you get an int. On failure you get false. A format character that is not recognised produces a warning and a false result. A format string that is not exactly one character is rejected as an invalid argument. If the default time zone is invalid, the date functions emit an E_WARNING.

The PHP 8.2.0 changelog notes that the N and o format characters were added, so avoid them on older runtimes.

Example 1: reading several parts of one timestamp

Because each call returns one part, you call idate() once per part. The timestamp 1700000000 is 2023-11-14 22:13:20 in UTC.

Example
<?php
date_default_timezone_set('UTC');
$ts = 1700000000;
echo json_encode([
    'year' => idate('Y', $ts),
    'month' => idate('m', $ts),
    'day' => idate('d', $ts),
    'hour' => idate('H', $ts),
    'minute' => idate('i', $ts),
    'second' => idate('s', $ts),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
Output
{"year":2023,"month":11,"day":14,"hour":22,"minute":13,"second":20}

Example 2: integers have no leading zeros

The most surprising behaviour is that a result such as 04 cannot exist as an integer. The leading zero is dropped, so the two-digit year of 2004 comes back as 4, and five minutes comes back as 5. When you need fixed-width text, pad it yourself.

Example
<?php
date_default_timezone_set('UTC');
$ts = 1072915500; // 2004-01-01 00:05:00 UTC
$year = idate('y', $ts);
$minute = idate('i', $ts);
echo json_encode([
    'year' => $year,
    'yearPadded' => sprintf('%02d', $year),
    'minute' => $minute,
    'minutePadded' => sprintf('%02d', $minute),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
Output
{"year":4,"yearPadded":"04","minute":5,"minutePadded":"05"}

Example 3: calendar facts for a date

Characters such as L, t, z, N and W turn idate() into a compact calendar helper. The timestamp below is 2024-02-10 12:00:00 UTC, a Saturday in a leap year.

Example
<?php
date_default_timezone_set('UTC');
$ts = 1707566400;
echo json_encode([
    'leap' => idate('L', $ts),
    'daysInMonth' => idate('t', $ts),
    'dayOfYear' => idate('z', $ts),
    'isoDow' => idate('N', $ts),
    'isoWeek' => idate('W', $ts),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
Output
{"leap":1,"daysInMonth":29,"dayOfYear":40,"isoDow":6,"isoWeek":6}

Notice that z is zero-based, so 10 February is reported as 40, not 41.

Edge cases

  • Week and year boundaries: the ISO week number W can belong to a different ISO year than the calendar year. Around the turn of the year, pair W with o, not Y.
  • Zero-based and one-based values: z starts at 0, w starts at 0 for Sunday, while N runs from 1 to 7. Mixing them up causes off-by-one bugs.
  • Time zone dependence: H, d, I, Z and several other characters depend on the default zone. A timestamp near midnight can land on different days in different zones.
  • Two-digit years: y returns a value from 0 to 99, so you cannot tell from the result alone which century it came from.
  • No timestamp means now: omitting the second argument makes the result change with the clock. That is fine in production code, but it makes tests unstable.

Common mistakes

  1. Passing a multi-character format such as 'Y-m-d'. idate() accepts one character, so call it once per part or use date() for a formatted string.
  2. Expecting zero-padded output. The value is an integer, so pad with sprintf() or str_pad() when you display it.
  3. Passing a date string instead of an integer timestamp. Convert strings first, for example with strtotime(), and check that conversion for failure.
  4. Forgetting to set the time zone, which leads to results that differ between servers.
  5. Treating the return value as always an int. The declared type is int|false, so strict code should guard against false.
  • date() formats a timestamp as a string and allows several characters at once.
  • getdate() returns many date parts in a single associative array.
  • DateTimeInterface::format() is the object-oriented equivalent of date().
  • time() returns the current Unix timestamp, which is what idate() uses by default.

Recap

idate() takes exactly one format character and an optional timestamp, and returns that part of the date as an integer, or false on failure. Set the time zone explicitly, remember that leading zeros disappear, and be careful with zero-based parts such as z and w. For anything that needs several parts or formatted text, use date(), getdate() or DateTimeInterface::format().

Tested examples

Reading several parts of one timestamp
<?php
date_default_timezone_set('UTC');
$ts = 1700000000;
echo json_encode([
    'year' => idate('Y', $ts),
    'month' => idate('m', $ts),
    'day' => idate('d', $ts),
    'hour' => idate('H', $ts),
    'minute' => idate('i', $ts),
    'second' => idate('s', $ts),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
Output
{"year":2023,"month":11,"day":14,"hour":22,"minute":13,"second":20}
Integers have no leading zeros
<?php
date_default_timezone_set('UTC');
$ts = 1072915500; // 2004-01-01 00:05:00 UTC
$year = idate('y', $ts);
$minute = idate('i', $ts);
echo json_encode([
    'year' => $year,
    'yearPadded' => sprintf('%02d', $year),
    'minute' => $minute,
    'minutePadded' => sprintf('%02d', $minute),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
Output
{"year":4,"yearPadded":"04","minute":5,"minutePadded":"05"}
Calendar facts for a date
<?php
date_default_timezone_set('UTC');
$ts = 1707566400;
echo json_encode([
    'leap' => idate('L', $ts),
    'daysInMonth' => idate('t', $ts),
    'dayOfYear' => idate('z', $ts),
    'isoDow' => idate('N', $ts),
    'isoWeek' => idate('W', $ts),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
Output
{"leap":1,"daysInMonth":29,"dayOfYear":40,"isoDow":6,"isoWeek":6}