Date Formatting

sa sahaya jerish Updated 17 Oct 2026
7 min read ·Lesson 102 of 109
In this post

What Is Date Formatting? In simple terms: Date formatting turns a date into text in a specific layout — 15/10/2026 for an Indian invoice, Thursday, 15 October 2026 for an event page, or 2026-10-15T14:

What Is Date Formatting?

In simple terms: Date formatting turns a date into text in a specific layout — 15/10/2026 for an Indian invoice, Thursday, 15 October 2026 for an event page, or 2026-10-15T14:05:09+05:30 for an API.

Technically: date() (for timestamps) and DateTimeInterface::format() (for date objects) accept a format string in which certain letters are replaced by parts of the date. Both use the same format characters.

date('d/m/Y', $timestamp);       // procedural
$dateTime->format('d/m/Y');      // object-oriented

All examples below use this date:

$d = new DateTimeImmutable('2026-10-15 14:05:09', new DateTimeZone('Asia/Kolkata'));

Format Characters

Day

CharacterMeaningExample
dDay of the month, two digits15 (05 for the 5th)
jDay of the month, no leading zero15 (5 for the 5th)
DShort weekday nameThu
l (lowercase L)Full weekday nameThursday
NISO weekday number (1 = Monday … 7 = Sunday)4
wWeekday number (0 = Sunday … 6 = Saturday)4
SEnglish ordinal suffix for the dayth (with j: 15th)
zDay of the year, starting at 0287

Week, Month, Year

CharacterMeaningExample
WISO week number42
mMonth, two digits10
nMonth, no leading zero10
MShort month nameOct
FFull month nameOctober
tNumber of days in the month31
LLeap year (1 or 0)0
YFour-digit year2026
yTwo-digit year26
oISO week-numbering year2026

Time

CharacterMeaningExample
HHour, 24-hour format, two digits14
GHour, 24-hour format, no leading zero14
hHour, 12-hour format, two digits02
gHour, 12-hour format, no leading zero2
iMinutes, two digits05
sSeconds, two digits09
A / aAM/PM or am/pmPM
v / uMilliseconds / microseconds000 / 000000

Time Zone and Full Formats

CharacterMeaningExample
eTime zone identifierAsia/Kolkata
TAbbreviationIST
POffset with colon+05:30
OOffset without colon+0530
cISO 8601 date and time2026-10-15T14:05:09+05:30
rRFC 2822 dateThu, 15 Oct 2026 14:05:09 +0530
UUnix timestamp1792053309

Characters that are not format letters (spaces, -, /, :, ,) appear in the output unchanged.


Common Formats

<?php
$d = new DateTimeImmutable('2026-10-15 14:05:09', new DateTimeZone('Asia/Kolkata'));

$formats = [
    'd/m/Y',
    'd-m-Y',
    'D, d M Y',
    'l, jS F Y',
    'h:i A',
    'g:i a',
    'Y-m-d H:i:s',
    DATE_ATOM,
    DATE_RFC2822,
];

foreach ($formats as $format) {
    echo str_pad($format, 18) . $d->format($format) . "\n";
}

Output

d/m/Y             15/10/2026
d-m-Y             15-10-2026
D, d M Y          Thu, 15 Oct 2026
l, jS F Y         Thursday, 15th October 2026
h:i A             02:05 PM
g:i a             2:05 pm
Y-m-d H:i:s       2026-10-15 14:05:09
Y-m-d\TH:i:sP     2026-10-15T14:05:09+05:30
D, d M Y H:i:s O  Thu, 15 Oct 2026 14:05:09 +0530

The last two lines show what the predefined constants contain: DATE_ATOM is Y-m-d\TH:i:sP (ISO 8601), and DATE_RFC2822 is D, d M Y H:i:s O.

Which Format for Which Purpose

PurposeFormatExample
Display in Indiad/m/Y or d M Y15/10/2026, 15 Oct 2026
Database DATETIME columnsY-m-d H:i:s2026-10-15 14:05:09
APIs, JSON, HTML <time>DATE_ATOM / c (ISO 8601)2026-10-15T14:05:09+05:30
Email headersDATE_RFC2822 / rThu, 15 Oct 2026 14:05:09 +0530
HTTP headers (Expires, cookies)DATE_RFC7231 (in UTC)Thu, 15 Oct 2026 08:35:09 GMT
File names, sortable keysYmd_His20261015_140509

Displaying dates as 15/10/2026 is fine for Indian users, but never store or exchange dates in local display formats: 05/06/2026 means 5 June in India and 6 May in the United States. ISO 8601 (2026-06-05) is unambiguous and sorts correctly as text.


Escaping Letters in the Format

Every format letter is replaced — even inside words. To print a letter literally, put a backslash before it:

<?php
$d = new DateTimeImmutable('2026-10-15 14:05:09', new DateTimeZone('Asia/Kolkata'));

echo $d->format('l the jS of F') . "\n";
echo $d->format('l \t\h\e jS \o\f F') . "\n";
echo $d->format('\D\a\t\e: d/m/Y') . "\n";

Output

Thursday 3102Asia/Kolkata 15th 2026f October
Thursday the 15th of October
Date: 15/10/2026

In the first line, the word "the" became 3102Asia/Kolkata: t is the number of days in the month (31), h the 12-hour hour (02), and e the time zone identifier. Likewise, o in "of" became the ISO year 2026, while f is not a format letter and stayed unchanged. Escaping each letter (\t\h\e, \o\f) prints the words as written. Use single quotes for format strings, so PHP does not interpret \t as a tab character.


Ordinal Suffixes

<?php
foreach ([1, 2, 3, 4, 11, 12, 13, 21, 22, 23] as $day) {
    $date = new DateTimeImmutable("2026-10-$day");
    echo $date->format('jS') . ' ';
}
echo "\n";

Output

1st 2nd 3rd 4th 11th 12th 13th 21st 22nd 23rd 

S handles the special cases (11th, 12th, 13th) correctly. It produces English suffixes only.


Localized Dates With IntlDateFormatter

date() and format() always produce English names (Thursday, October). For other languages, use IntlDateFormatter from the intl extension, which uses the internationalization data of the ICU library:

<?php
$d = new DateTimeImmutable('2026-10-15 14:05:09', new DateTimeZone('Asia/Kolkata'));

foreach (['en_IN', 'ta_IN', 'hi_IN'] as $locale) {
    $formatter = new IntlDateFormatter(
        $locale,
        IntlDateFormatter::NONE,
        IntlDateFormatter::NONE,
        'Asia/Kolkata',
        IntlDateFormatter::GREGORIAN,
        'd MMMM y'
    );

    echo $locale . ': ' . $formatter->format($d) . "\n";
}

Output (exact text can vary slightly between ICU versions)

en_IN: 15 October 2026
ta_IN: 15 அக்டோபர் 2026
hi_IN: 15 अक्तूबर 2026
  • The pattern d MMMM y uses ICU pattern letters, which differ from PHP's date() letters (MMMM is the full month name, y the year).
  • Instead of a pattern, predefined styles such as IntlDateFormatter::LONG produce the conventional format for each locale.
  • The intl extension must be installed (it is included in most PHP distributions and Docker images).

Relative Formatting: "5 Minutes Ago"

Social feeds and comment sections often show relative times. A small function can produce them:

<?php
function timeAgo(DateTimeInterface $then, DateTimeInterface $now): string
{
    $seconds = $now->getTimestamp() - $then->getTimestamp();

    if ($seconds < 60) {
        return 'just now';
    }

    if ($seconds >= 7 * 86400) {
        return 'on ' . $then->format('d M Y');
    }

    foreach ([['day', 86400], ['hour', 3600], ['minute', 60]] as [$unit, $size]) {
        if ($seconds >= $size) {
            $count = intdiv($seconds, $size);
            return $count . ' ' . $unit . ($count === 1 ? '' : 's') . ' ago';
        }
    }

    return 'just now';
}

$now = new DateTimeImmutable('2026-10-15 14:05:09', new DateTimeZone('Asia/Kolkata'));

foreach (['-30 seconds', '-1 minute', '-5 minutes', '-3 hours', '-2 days', '-10 days'] as $offset) {
    echo str_pad($offset, 12) . timeAgo($now->modify($offset), $now) . "\n";
}

Output

-30 seconds just now
-1 minute   1 minute ago
-5 minutes  5 minutes ago
-3 hours    3 hours ago
-2 days     2 days ago
-10 days    on 05 Oct 2026

How It Works

  1. The difference in seconds is calculated from the timestamps.
  2. Anything under a minute is "just now"; anything older than a week shows the actual date, because "47 days ago" is less useful than a date.
  3. The loop picks the largest fitting unit and adds an "s" for plurals.
  4. $now is a parameter instead of being created inside the function, which makes the function testable with fixed dates — as in this example.

When displaying relative times, include the exact time in the HTML for accessibility and tooltips: <time datetime="2026-10-15T14:05:09+05:30" title="15 Oct 2026, 2:05 PM">5 minutes ago</time>.


Common Mistakes

Confusing m and i

Effect: H:m prints the month instead of minutes (14:10).

Fix: Minutes are i; month is m.

Confusing l and L

Effect: L prints 0/1 (leap year) instead of the weekday.

Fix: The weekday name is lowercase l.

Unescaped Letters in Text

Effect: Words inside the format are replaced by date values.

Fix: Escape literal letters with a backslash, and use single-quoted strings.

Storing Display Formats

Effect: Ambiguous dates (05/06/2026) and incorrect sorting.

Fix: Store Y-m-d / ISO 8601; format only for display.

Expecting date() to Translate

Effect: English month names on a Tamil or Hindi website.

Fix: Use IntlDateFormatter.


Best Practices

  • Use DateTimeImmutable::format() with explicit time zones for all display formatting.
  • Use ISO 8601 for storage and data exchange, and local formats only for display.
  • Use the predefined constants (DATE_ATOM, DATE_RFC2822, DATE_RFC7231) for standard formats.
  • Escape literal letters and keep format strings in single quotes.
  • Use IntlDateFormatter for non-English output, and keep relative-time functions testable by passing "now" in.

Official reference: https://www.php.net/manual/en/datetime.format.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators
Ask about this post
AI Ask about this post

Ask questions about Date Formatting and get answers drawn from it.

Signed-in readers only.