Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

"First Day of Next Month": PHP Date Phrases You Should Steal

C
Carlo Fontanos
· 2 min read

I once reviewed a 40-line function that calculated the last day of a billing month with loops and cal_days_in_month. It was correct, tested... and replaceable with a string:

$end = new DateTimeImmutable('last day of this month');

PHP's date parser understands a compact English grammar, and the phrases compose into most calendar logic you'll ever need.

The phrases that earn their keep

new DateTimeImmutable('first day of next month');     // billing cycle start
new DateTimeImmutable('last day of previous month');  // report ranges
new DateTimeImmutable('second friday of january 2027');  // scheduling rules
new DateTimeImmutable('last friday of this month');   // "payday" logic
new DateTimeImmutable('monday this week');            // week bucketing
new DateTimeImmutable('yesterday midnight');          // clean day boundaries
new DateTimeImmutable('+3 weekdays');                 // business-ish days

They chain in one string, evaluated left to right: 'first day of next month midnight' gives you an exact boundary timestamp with no setTime() ceremony.

The trap everyone hits once: "next month" near month-end

// On January 31:
(new DateTimeImmutable('2026-01-31'))->modify('+1 month');
// => March 3rd. Not February anything.

"+1 month" adds a month numerically (Jan 31 → Feb 31) and then normalizes the overflow into March. It's documented, deterministic, and has ruined countless monthly-subscription implementations. The idiom that behaves the way humans expect:

$next = $date->modify('first day of next month');   // anchor first - overflow impossible
// then place the day-of-month with a min() against that month's length

Anchoring to "first day of" before any month arithmetic is the reliable pattern - it's immune to overflow by construction.

Immutable, always

$start = new DateTime('today');
$end   = $start->modify('+30 days');   // DateTime: $start CHANGED TOO

Mutable DateTime's modify() alters the original and returns it - a shared-reference bug generator. DateTimeImmutable has the same API but returns new objects, making the code above correct by default. There is essentially no reason to use mutable DateTime in new code.

Bonus: the same grammar works everywhere dates are parsed

strtotime('last day of next month'), the DateTime constructor, and modify() all share the parser - learn the grammar once, use it in all three. For formatting the results per-locale, that's IntlDateFormatter territory (the PHP cousin of JavaScript's Intl formatting).

Calendar math is where hand-rolled cleverness goes to spawn edge cases. The parser has already survived twenty years of them - let it do the thinking.

C
Written by Carlo Fontanos

Full-stack web developer sharing practical tutorials and building tools that ship.

Got something on your mind?

My inbox is open - no forms disappearing into the void here.

  • Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
  • Hire me for a project Have something custom in mind? Let's talk scope and timelines.
  • Product support Bought something here? I'll help you get it running.

I usually reply within 1-2 business days.

Message sent!

Your details are only used to reply to you.

Keep reading