Dates7 min readExamples run on PHP 8.5.10

date_interval_format()

Learn how date_interval_format() turns a DateInterval into text using format tokens such as %d, %H and %R, with examples, edge cases and common mistakes.

Signature

date_interval_format(DateInterval $object, string $format): string
Available since PHP 5.3.07.48.08.18.28.38.48.5All versions →

Purpose

date_interval_format() is the procedural alias of DateInterval::format(). It takes a DateInterval object and a format string, and returns a string in which each recognized token is replaced by a value from the interval. You use it to show a duration to a person: "2 days 3 hours", "+30 days", or a clock-like 04:05:06.

The function describes an interval; it does not do date arithmetic. It reads the stored fields (years, months, days, hours, minutes, seconds, microseconds, sign) and prints them as they are.

Signature

The object-oriented equivalent is $interval->format($format). Both behave identically.

Parameters

  • $object: the DateInterval to print. It can come from new DateInterval('P1D') or from date_diff(). It has no default.
  • $format: the template string. It has no default. Any text that is not a token is copied unchanged.

Every token starts with a percent sign. The ones you will use most:

  • %y / %Y: years, plain or padded to at least 2 digits
  • %m / %M: months, plain or padded to 2 digits
  • %d / %D: days, plain or padded to 2 digits
  • %h / %H: hours, plain or padded to 2 digits
  • %i / %I: minutes, plain or padded to 2 digits
  • %s / %S: seconds, plain or padded to 2 digits
  • %f / %F: microseconds, plain or padded to 6 digits
  • %a: total number of days, only when the interval came from a date difference; otherwise the text (unknown)
  • %R: sign, always + or -
  • %r: sign, - when negative and empty when positive
  • %%: a literal percent sign

Return value and failure cases

The function always returns a string. Passing something that is not a DateInterval as the first argument, or a value that cannot be used as a string for $format, raises a TypeError. Unknown tokens do not raise an error: the percent sign and the following character are left in the output as written.

Example 1: plain and padded tokens

Lowercase tokens print the raw number, while uppercase tokens pad it. Padding is handy for clock-like output.

Example
<?php
$interval = new DateInterval('P1Y2M3DT4H5M6S');
echo date_interval_format($interval, '%y-%m-%d %h:%i:%s'), "\n";
echo date_interval_format($interval, '%Y-%M-%D %H:%I:%S'), "\n";
Output
1-2-3 4:5:6
01-02-03 04:05:06

Example 2: total days and the sign

When an interval is produced by date_diff(), %a holds the total number of days between the two dates. %R shows whether the second date lies before the first.

Example
<?php
date_default_timezone_set('UTC');
$start = new DateTimeImmutable('2024-01-31');
$end = new DateTimeImmutable('2024-03-01');

echo date_interval_format(date_diff($start, $end), '%R%a days'), "\n";
echo date_interval_format(date_diff($end, $start), '%R%a days'), "\n";
Output
+30 days
-30 days

Example 3: no normalization, literal percent, unknown total

An interval built from a specification keeps exactly the numbers you gave it. PT90S is 90 seconds, not 1 minute 30 seconds, and %a is unknown because no two dates were compared.

Example
<?php
$interval = new DateInterval('PT90S');
$parts = [
    date_interval_format($interval, '%i:%s'),
    date_interval_format($interval, '%s%%'),
    date_interval_format($interval, '%a'),
];
echo json_encode($parts, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["0:90","90%","(unknown)"]

Edge cases

  • No carrying over. The function never converts 90 seconds into minutes, or 25 hours into a day. If you need that, build the interval from a real date difference or normalize the values yourself.
  • %a is not always a number. Only intervals created by a date difference carry a total day count. For a constructed interval, the result is the string (unknown).
  • Sign handling. The numeric fields of a DateInterval are stored as non-negative numbers, and a separate invert flag records direction. %R always prints a sign, while %r prints one only for negative intervals. Choose %r when you want "-5" for negatives and "5" for positives.
  • Month and day parts of a diff. For a date difference, the %m and %d parts depend on the calendar dates involved. Use %a when you want an exact number of days.
  • Unknown tokens. A sequence like %z is not replaced and stays in the output, which can look like a bug in a template.

Common mistakes

  1. Using date() tokens. Tokens like %Y here mean years in the interval, not a calendar year. Formats such as Y-m-d without percent signs are copied literally.
  2. Forgetting the percent sign. d prints the letter d, while %d prints the days.
  3. Expecting %a on a manual interval. It prints (unknown). Compare two dates with date_diff() if you need total days.
  4. Confusing %R and %r. %R yields + for positive intervals, which may be unwanted in user-facing text.
  5. Mixing up %M and %I. Uppercase M is months and uppercase I is minutes. Using %M for minutes is a frequent error.
  6. Escaping a literal percent sign. To print %, write %%.
  • DateInterval::format(): the method this function aliases
  • date_diff(): creates an interval between two dates
  • date_interval_create_from_date_string(): builds an interval from text like 3 days
  • date_add() and date_sub(): apply an interval to a date
  • date_format(): formats a date rather than an interval

Recap

date_interval_format() takes a DateInterval and a template and returns a string. Lowercase tokens print raw values, uppercase tokens pad them, %R and %r show the sign, %a gives total days only for date differences, and %% prints a percent sign. Nothing is normalized, so what you stored is what you print.

Tested examples

Plain and padded tokens
<?php
$interval = new DateInterval('P1Y2M3DT4H5M6S');
echo date_interval_format($interval, '%y-%m-%d %h:%i:%s'), "\n";
echo date_interval_format($interval, '%Y-%M-%D %H:%I:%S'), "\n";
Output
1-2-3 4:5:6
01-02-03 04:05:06
Total days and the sign from date_diff()
<?php
date_default_timezone_set('UTC');
$start = new DateTimeImmutable('2024-01-31');
$end = new DateTimeImmutable('2024-03-01');

echo date_interval_format(date_diff($start, $end), '%R%a days'), "\n";
echo date_interval_format(date_diff($end, $start), '%R%a days'), "\n";
Output
+30 days
-30 days
No normalization, literal percent, unknown total
<?php
$interval = new DateInterval('PT90S');
$parts = [
    date_interval_format($interval, '%i:%s'),
    date_interval_format($interval, '%s%%'),
    date_interval_format($interval, '%a'),
];
echo json_encode($parts, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
["0:90","90%","(unknown)"]