Dates & Times (DateTime)

Dates are deceptively tricky — timezones, leap years, daylight saving, formatting. PHP's DateTimeImmutable handles all of it for you. Learn to create, format, do arithmetic on, and compare dates safely, and you'll never reach for raw timestamp maths again.

Learn Dates & Times (DateTime) in our free PHP course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.

Part of the free Php course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Creating Dates

Build a date by passing a string to new DateTimeImmutable(...) . It accepts ISO dates ( '2026-01-15' ), full timestamps, and even friendly phrases like 'now' , 'next friday' or '+2 weeks' . To turn an object back into text, call format() with format letters .

2️⃣ Formatting with format()

The format string is a recipe of single letters, where case matters : Y is a four-digit year, m a zero-padded month, d a zero-padded day, H:i:s 24-hour time. Any letter you want printed literally must be escaped with a backslash — that's why the ISO example below has \T .

3️⃣ Date Arithmetic

To move a date forwards or backwards, describe the span with a DateInterval and call add() or sub() . The interval string starts with P (period) and uses T before time parts: P10D is ten days, PT2H30M is two and a half hours. For quick phrases, modify('+3 days') is even handier. Because the object is immutable, each call returns a new date and leaves the original alone.

4️⃣ Comparing Dates with diff()

To find the gap between two dates, call $a->diff($b) , which returns a DateInterval you can read or format. Use ->days for the true total number of days, the broken-down ->y/->m/->d for years/months/days, and ->invert (which is 1 ) to tell direction. You can also compare two date objects directly with < , > and == .

5️⃣ Parsing & Timezones

When a string isn't in a standard format — say 18/06/2026 — tell PHP the layout with createFromFormat() . For correct times, attach a DateTimeZone when you build the date, then setTimezone() to convert it for display. Storing in UTC and converting only at render time is the pattern that keeps you out of daylight-saving trouble.

Now you try — fill in each ___ using the 👉 hint, then run it and check against the Output panel.

These lines compute a date one week from a start date — but they're scrambled. Put them in the order that prints 2026-06-25 .

Create the start date ( B ) and the interval ( C ) — order between these two doesn't matter — then add them to get a new date ( D ), and finally format it ( A ). You can't reference $next before it exists.

2026-06-18 — the object is immutable , so modify() returns a new object that was never captured. The original is unchanged. (You'd need $d = $d->modify(...) .)

10 — ->days is the total number of days between the two dates.

3. What does format('jS') output for the 3rd?

3rd — j is the day without a leading zero and S adds the English ordinal suffix.

📋 Quick Reference — Dates

No code is filled in this time — just a brief and an outline. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments.

Practice quiz

Why is DateTimeImmutable preferred over the mutable DateTime?

  • It is faster
  • It supports more timezones
  • Every operation returns a new object, leaving the original untouched
  • It uses less memory

Answer: Every operation returns a new object, leaving the original untouched. DateTimeImmutable returns a brand-new object from every operation and never alters the original, avoiding a whole class of bugs.

What prints? $d = new DateTimeImmutable('2026-06-18'); $d->modify('+1 day'); echo $d->format('Y-m-d');

  • 2026-06-18
  • 2026-06-19
  • 2026-06-17
  • It throws an error

Answer: 2026-06-18. On an immutable object, modify() returns a NEW object that was never captured. The original is unchanged, so it prints 2026-06-18.

In a format string, what does a capital Y produce versus a lowercase y?

  • Both give four digits
  • Y is two digits, y is four digits
  • y is the month
  • Y is four digits (2026), y is two digits (26)

Answer: Y is four digits (2026), y is two digits (26). Case matters: capital Y is a four-digit year (2026); lowercase y is two digits (26).

Which method returns a DateInterval describing the gap between two dates?

  • gap()
  • diff()
  • between()
  • minus()

Answer: diff(). $a->diff($b) returns a DateInterval you can read or format.

On the interval from diff(), what does the ->days property give?

  • The total absolute number of days between the two dates
  • Leftover days after whole years/months
  • The day-of-month number
  • Always 0

Answer: The total absolute number of days between the two dates. ->days is the true total number of days, whereas ->d is only the leftover days after whole years and months are accounted for.

What is the DateInterval period string for seven days?

  • D7
  • 7D
  • P7D
  • PT7D

Answer: P7D. Interval strings start with P (period); P7D is seven days. T appears only before time parts like hours/minutes.

Which prefix marks the time portion of a DateInterval string, as in PT2H30M?

  • P
  • T
  • H
  • I

Answer: T. P starts the period; T precedes the time part, so PT2H30M is 2 hours 30 minutes.

Which method parses a string in a custom layout like '18/06/2026'?

  • strtotime()
  • parse()
  • fromString()
  • createFromFormat()

Answer: createFromFormat(). DateTimeImmutable::createFromFormat('d/m/Y', '18/06/2026') tells PHP the exact layout to parse.

What does the ->invert property of a DateInterval indicate?

  • The number of leap years
  • It is 1 when the second date is earlier than the first
  • Whether the interval is negative days
  • The timezone offset

Answer: It is 1 when the second date is earlier than the first. ->invert is 1 when the second date passed to diff() is before the first, telling you the direction.

What is the recommended pattern for storing and displaying times across timezones?

  • Store local time, never convert
  • Use the server default everywhere
  • Store everything in UTC and convert to local only when rendering
  • Avoid DateTimeZone entirely

Answer: Store everything in UTC and convert to local only when rendering. Store and compute in UTC, then convert with setTimezone() only at display time, to avoid daylight-saving and server-location surprises.