Skip to content

Subtracting 1 month from a DateTime or DateTimeImmutable #12477

@sjoller

Description

@sjoller

Description

The following code:

<?php
$expirationDate = new DateTimeImmutable('2025-12-31 23:59:59');

echo $expirationDate->format('Y-m-d H:i:s') . chr(10);


$newDate = $expirationDate->modify('-1 day');

echo $newDate->format('Y-m-d H:i:s') . chr(10);

$newDate = $expirationDate->modify('-1 month');

echo $newDate->format('Y-m-d H:i:s') . chr(10);

$newDate = $expirationDate->modify('-2 month');

echo $newDate->format('Y-m-d H:i:s') . chr(10);

3v4l.org link

Resulted in this output:

2025-12-31 23:59:59
2025-12-30 23:59:59
2025-12-01 23:59:59 <- Not a full month subtracted
2025-10-31 23:59:59

But I expected this output instead:

2025-12-31 23:59:59
2025-12-30 23:59:59
2025-11-30 23:59:59 <- What I need it to be
2025-10-31 23:59:59

As shown, $expirationDate is set correctly and prints out as expected.
Subtracting 1 day works as expected too, but then subtracting 1 month does not work - it subtracts 30 days, not the full 31 days of December month, landing me on the first day of December, not the last day of November.
Finally subtracting 2 months again works as expected, subtracting the required 61 days, landing me squarely on the last day of October.

Originally I used $expirationDate->sub(new DateInterval('P1M')) (using a DateTime object), but that did the exact same thing.

I'm fairly sure it's not my setup acting wierd - testing on https://onlinephp.io/ yields the same results

PHP Version

PHP 8.2.11 (and PHP 7.4.x)

Operating System

Debian BookWorm (WSL)

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions