Our PHP TimeTraveler to address DateTime::modify() pitfalls

Sylvain FabreSylvain Fabre
2 min read

Everybody knows the PHP native method DateTime::modify()

The DateTime extension supports awesome modifiers like "2 days ago", "last day of this month", ... or basic ones like "+1 month".

But the last one is actually tricky: it increments the month value of the date.

For instance 2023-01-01 (January first) becomes 2023-(01+1)-01 => 2023-02-01

But as not all months last 31 days: incrementing one month on 2023-08-31 results to 2023-09-31 which doesn't exist and is thus corrected to 2023-10-01.

If you keep playing, you will notice that modify('+1 year') returns a different date than calling 12 times modify('+1 month') 🤯

(new DateTime('2023-01-31'))->modify('+1 year'); // 2024-01-31
(new DateTime('2023-01-31'))
    ->modify('+1 month') // 2023-03-03 which is the root cause
    ...
    ->modify('+1 month'); // 2024-02-03

At AssoConnect, we deal with monthly and yearly subscriptions, memberships, ... so we need reliable and predictable date operations.

The latest release of our https://github.com/assoconnect/php-date library brings a month & year traveler with 3 main features:

  1. The last day of the month is sticky

    September, 30th + 1 month = October, 31st instead of 30th

  2. A month is never skipped

    January, 30th + 1 month = February, 28th (or 29th) instead of March, 1st

    February, 29th + 1 year = February, 28th instead of March, 1st

  3. The year-over-year result is consistent with the initial reference

    January, 30th + (1 month) x 12 = January, 30th instead of February, 2nd

We published this library under the MIT license so feel free to use it!

0
Subscribe to my newsletter

Read articles from Sylvain Fabre directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sylvain Fabre
Sylvain Fabre

10+ years experience as CTO at AssoConnect. We are helping nonprofits change the world with an all-in-one software to save time on daily management.