PHP Date Format
PHP’s built-in date() function is a powerful tool for formatting dates and time, but its real potential becomes clear when you start exploring advanced use cases. In this post, we’ll cover:
- The basics recap
- Advanced format characters
- Combining formats for locale-aware output
- Relative/conditional formatting
- Timezone handling
- Custom date formatting via DateTime
- Performance considerations
- Best practices and pitfalls
1. Quick Recap: The Fundamentals
echo date('Y-m-d H:i:s'); // 2025-06-22 14:45:03- Y – 4-digit year
- y – 2-digit year
- m – 2-digit month
- n – month (1–12) without leading zero
- d – 2-digit day of month
- j – day without leading zero
- H – 24‑hr hour
- h – 12‑hr hour
- i – minutes
- s – seconds
These basics are well-known. But PHP supports dozens more format specifiers. Let’s explore some advanced options.
2. Advanced Format Characters
2.1 Day, Week, and Year info
- D – Three-letter weekday (Mon, Tue)
- l (lowercase ‘L’) – Full weekday (Monday, Tuesday)
- N – ISO weekday as number (1 = Monday…7 = Sunday)
- w – Numeric weekday (0 = Sunday…6 = Saturday)
- z – Day of year starting from 0
- W – ISO week number (weeks starting Monday, week 1 has Jan 4)
echo date('l, \t\h\\e jS \o\f F Y') . "\n";
// Example: "Sunday, the 22nd of June 2025"
echo date('W') . "\n"; // ISO week number (e.g., "25")
echo date('z') . "\n"; // Day of year zero-indexed (e.g., "173")2.2 Month/Quarter Info
- F – Full month text (January–December)
- M – Short month text (Jan–Dec)
- n – Numeric month without leading zeros (1–12)
- t – Number of days in current month
echo date('F') . "\n"; // "June"
echo date('t') . "\n"; // "30"2.3 Time and Timezone Info
- a, A – am/pm
- g, G – 12‑hr/24‑hr format without leading zeros
- U – Unix timestamp
- e, T – Timezone identifier / abbreviation
- O, P, Z – UTC offset formats and offset in seconds
echo date('g:ia T') . "\n"; // e.g. "2:45pm UTC"
echo date('P') . "\n"; // e.g. "+00:00"
echo date('Z') . "\n"; // "0" (offset secs)
echo time() . "\n"; // Current timestamp, same as U
echo date('r') . "\n"; // RFC 2822 date: "Sun, 22 Jun 2025 14:45:03 +0000"2.4 Escape Sequences
To literally output characters like S or j, prefix with backslash:
echo date('\T\o\d\a\y \i\s l') . "\n";
// "Today is Sunday"3. Combining Formats for Localization
While PHP’s date() offers robust formatting, it’s not locale-aware (always English). Combine with strftime() or IntlDateFormatter for other languages:
setlocale(LC_TIME, 'fr_FR.UTF-8');
echo strftime('%A %e %B %Y, %H:%M') . "\n";
// "dimanche 22 juin 2025, 14:45"With Intl:
$fmt = new IntlDateFormatter(
'fr_FR',
IntlDateFormatter::FULL,
IntlDateFormatter::SHORT,
'Europe/Paris',
IntlDateFormatter::GREGORIAN
);
echo $fmt->format(new DateTime());3.1 Date in Words
echo strftime('%d %b %Y') . "\n"; // 22 Jun 2025 (fr_FR -> "22 juin 2025")4. Relative/Conditional Formatting
Dynamic formatting based on how "old" a date is:
function human_diff(DateTime $dt, DateTime $now = null) {
$now = $now ?: new DateTime('now', $dt->getTimezone());
$diff = $now->diff($dt);
if ($diff->y) return $diff->y . ' year' . ($diff->y>1?'s':'') . ' ago';
if ($diff->m) return $diff->m . ' month' . ($diff->m>1?'s':'') . ' ago';
if ($diff->d) return $diff->d . ' day' . ($diff->d>1?'s':'') . ' ago';
if ($diff->h) return $diff->h . ' hour' . ($diff->h>1?'s':'') . ' ago';
if ($diff->i) return $diff->i . ' minute' . ($diff->i>1?'s':'') . ' ago';
return 'just now';
}
echo human_diff(new DateTime('-3 hours')); // "3 hours ago"Add today/yesterday/tomorrow text:
function smart_date(DateTime $dt) { /* logic with midnight and date comparison */}5. Timezone Handling
Be explicit:
$date = new DateTime('2025-06-22 14:45:03', new DateTimeZone('UTC'));
$date->setTimezone(new DateTimeZone('America/New_York'));
echo $date->format('Y-m-d H:i T'); // "2025-06-22 10:45 EDT"Parse with PHP’s DateTime::createFromFormat():
$date = DateTime::createFromFormat('d/m/Y H:i:s', '31/12/2025 23:59:59');
echo $date->format('Y-m-d H:i:s');6. Custom Formats with DateTime
DateTimeInterface + format():
$dt = new DateTime('2025-06-22T14:45:03+02:00');
// RFC 3339:
echo $dt->format(DateTime::RFC3339) . "\n";
// ISO8601:
echo $dt->format(DateTime::ISO8601) . "\n";
// Atom:
echo $dt->format(DateTime::ATOM) . "\n";
Add microseconds:
$now = DateTime::createFromFormat('U.u', microtime(true));
echo $now->format('Y-m-d H:i:s.u'); // 2025-06-22 14:45:03.123456Custom relative format with conditionals:
$parts = [];
if ($diff->h) $parts[] = $diff->h . 'h';
if ($diff->i) $parts[] = $diff->i . 'm';
echo implode('', $parts);7. Performance Tips
- Reuse DateTimeZone objects
- Avoid date() and strtotime() repeatedly in loops
- Microbenchmarks:
$start = microtime(true);
for ($i=0; $i<1e5; $i++) {
DateTime::createFromFormat('U', time());
}
echo (microtime(true) - $start);date() is faster but less flexible.
8. Best Practices & Pitfalls
- Never assume server timezone – set date_default_timezone_set() or use DateTimeZone.
- Avoid strtotime() with ambiguous strings – be specific.
- Use ISO 8601 or RFC3339 when storing dates.
- Escape carefully.
- Be locale-aware if internationalization is required.
9. Advanced Recipes
9.1 Next N occurrence:
function nextByWeekday($weekday, $timezone='UTC') {
$ts = strtotime("next $weekday");
return date('Y-m-d', $ts);
}9.2 Is it a leap year?
function isLeap($year=null) {
$year = $year ?: date('Y');
return ((($year % 4 == 0) && ($year %100 != 0)) || ($year % 400 == 0));
}9.3 Quarter:
function getQuarter(DateTime $d){
return ceil((int)$d->format('n')/3);
}9.4 Business days between dates:
function businessDays($from, $to) {
$start = new DateTime($from);
$end = new DateTime($to);
$count = 0;
while ($start <= $end) {
$w = $start->format('N');
if ($w < 6) $count++;
$start->modify('+1 day');
}
return $count;
}Conclusion
- PHP’s date() function is just the tip of the iceberg.
- Combine with DateTime, IntlDateFormatter, and smart functions for powerful date logic.
- Handy recipes for business days, quarters, and smart relative labels.
- Always mind timezone, performance, and localization.