Carbon: Why does subMonth not work correctly?
It is currently 11:50pm local time on 31st August 2015.
Why do I get the incorrect date when doing subMonth functions? Is Carbon not able to handle 30 and 31 months? 😦
var_dump(\Carbon\Carbon::now());
Carbon {#520 ▼
+"date": "2015-08-31 14:00:07.000000"
+"timezone_type": 3
+"timezone": "UTC"
}
var_dump(\Carbon\Carbon::now()->subMonth(1));
Carbon {#521 ▼
+"date": "2015-07-31 14:00:07.000000"
+"timezone_type": 3
+"timezone": "UTC"
}
var_dump(\Carbon\Carbon::now()->subMonth(2));
Carbon {#522 ▼
+"date": "2015-07-01 14:00:07.000000" // <- WRONG - I would have expected 2015-06-30?
+"timezone_type": 3
+"timezone": "UTC"
}
var_dump(\Carbon\Carbon::now()->subMonth(3));
Carbon {#523 ▼
+"date": "2015-05-31 14:00:07.000000"
+"timezone_type": 3
+"timezone": "UTC"
}
put another way: The output is “August, July, July, May” - but obviously I want “August, July, June, May”.
How do I always safely get the previous X month?
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Reactions: 4
- Comments: 20 (5 by maintainers)
Checkout
addMonthsNoOverflow
@Noushid use
subMonthsNoOverflow
@briannesbitt - are you open to changing this in a major tag?
I cannot think of an instance when doing
->subMonth(1)
that it would be acceptable to not get the month “1” ago? It would seem a trap that most developers would probably fall into (like I did)?And what makes it worse - is it is very unlikely to be detected during development, and only show up on the 31st of a month (like what occurred to me).
I reckon it would be a silent bug in many applications? Because doing
->subMonth(1)
would imply you explicitly want to know what the previous month was?If I was doing
->subDays(30)
- then I am saying that I want 30 days ago - But if I am doing->subMonth(1)
- then I am explicitly asking for the month ago?Basically it should always be M-1?
Thoughts?
@briannesbitt The point of Carbon among other things is to overwrite/fix the inconsistent or wrong behavior of PHP DateTime, right? Otherwise we could all just use the native code. So it would make sense to be more consistent with the developer’s expectations then the often times quite buggy core behavior IMO.
Its based on the underlying PHP behaviour for “consistency”.
Not saying its right or wrong, but you can see its not really adding 30 days but ++ the month and then doing overflow since the resulting day doesn’t really exist.
I have same Issue please go through below code. Code
Result
This is indeed broken usability at it’s finest! There’s probably no developer in the world who expects 1st of January when doing
subMonth()
on January 31st. This is nuts. To be fair, it’s PHP’s fault, as the underlaying PHP date engine is doing this horribly wrong.Hey community, maybe it’s time to get it on and fix this shit in PHP8. I’m in 😃
Yeah - I understand.
I had a look - doesnt seem to be mentioned anywhere in the docs? Should probably be right next to the add/sub methods so people are aware.
Thinking aloud - if I did subYear on a leap year on NYE - I would get the same problem?
But is it really expected behavior?
If you do
->subMonth(2)->format('M')
- then you would always expect the result to be 2 months earlier… anything else feels wrong?