Reputation: 512
I found a weird result when I use diffInMonths of laravel Carbon. Can anyone explain for me why it works like this. Is it a bug? And how to get it correct.
$d1 = new Carbon('2018-02-01');
$d2 = new Carbon('2018-03-01');
dd($d1->diffInMonths($d2));
Output was: 0 (Expected: 1)
BUT
$d1 = new Carbon('2018-02-02');
$d2 = new Carbon('2018-03-02');
dd($d1->diffInMonths($d2));
Output was: 1
My setting timezone is "Asia/Ho_Chi_Minh" (GMT +7). PHP Version 7.0.22. OS: Ubuntu Server 16.04
This weird result happends only between February 1 and March 1, other months result as expected.
I also try date_diff
instead of Carbon
$d1 = new \DateTime('2018-02-01');
$d2 = new \DateTime('2018-03-01');
$diff = date_diff($d1,$d2);
dump($diff->m);
dump($diff->d);
die;
It returns months: 0, and days: 28 (Not month: 1, days: 0 as expected)
So the problem may be from PHP not from Carbon.
Upvotes: 2
Views: 4530
Reputation: 469
Very peculiar behaviour:
$jan = new Illuminate\Support\Carbon("2022-01-01");
$feb = new Illuminate\Support\Carbon("2022-02-01");
$mar = new Illuminate\Support\Carbon("2022-03-01");
$feb->diffInMonths($mar); // 0
$feb->floatDiffInMonths($mar); // 1.0
$jan->diffInMonths($mar); // 1
$jan->floatDiffInMonths($mar); // 2.0
Solution
Use intval on floatDiffInMonths:
intval($feb->floatDiffInMonths($mar)); // 1
intval($jan->floatDiffInMonths($mar)); // 2
Upvotes: 2
Reputation: 1
The same story, finally wrote my own function for calculating month difference:
function month_diff(\Carbon\Carbon $date1, \Carbon\Carbon $date2){
$ts1 = $date1->startOfDay()->getTimestamp();
$ts2 = $date2->startOfDay()->getTimestamp();
$year1 = intval(date('Y', $ts1));
$year2 = intval(date('Y', $ts2));
$month1 = intval(date('m', $ts1));
$month2 = intval(date('m', $ts2));
$day1 = intval(date('d', $ts1));
$day2 = intval(date('d', $ts2));
$res = (($year2 - $year1) * 12) + ($month2 - $month1) - (($day2 >= $day1) ? 0 : 1);
return $res >= 0 ? $res : 0; }
here, pay attention to the days of the month too, also may take time into account too.
Upvotes: 0
Reputation: 685
I encountered the same thing, but the above methods doesn't work for me. So I write this and it works perfectly fine.
$prevMonth = Carbon::parse("01-02-2019");
$thisMonth = Carbon::parse("01-03-2019");
$part1 = ($prevMonth->format('Y') * 12) + $prevMonth->format('m');
$part2 = ($thisMonth->format('Y') * 12) + $thisMonth->format('m');
$diff = abs($part1 - $part2); // To make the result always positive abs()
Result:-
1 // with abs()
-1 // without abs()
Upvotes: 0
Reputation: 768
I think setting the timezone to UTC should solve this. I had the same problem when the timezone was set to Europe/Zurich
:
>>> $last = new \Carbon\Carbon('2019-02-01');
=> Carbon\Carbon @1548975600 {#2381
date: 2019-02-01 00:00:00.0 Europe/Zurich (+01:00),
}
>>> $now = (\Carbon\Carbon::now())->day(1)->setTime(0, 0, 0);
=> Carbon\Carbon @1551394800 {#2371
date: 2019-03-01 00:00:00.0 Europe/Zurich (+01:00),
}
>>> $now->diffInMonths($last)
=> 0
After changing the timezone to UTC:
>>> $last = new \Carbon\Carbon('2019-02-01', 'UTC');
=> Carbon\Carbon @1548979200 {#2380
date: 2019-02-01 00:00:00.0 UTC (+00:00),
}
>>> $now = (\Carbon\Carbon::now('UTC'))->day(1)->setTime(0, 0, 0);
=> Carbon\Carbon @1551398400 {#2394
date: 2019-03-01 00:00:00.0 UTC (+00:00),
}
>>> $now->diffInMonths($last)
=> 1
Upvotes: 1
Reputation:
The code you provided should work. Although you can try alternative of Carbon. Try DateTime
$d1 = new DateTime('2018-02-01');
$d2 = new DateTime('2018-03-01');
$diff = date_diff($d1,$d2);
dd($diff->m);
Upvotes: 1
Reputation: 2469
You should set timezone in Carbon, Now it works:
Carbon::now(new \DateTimeZone('Asia/Ho_Chi_Minh'));
$d1 = new Carbon('2018-02-01');
$d2 = new Carbon('2018-03-01');
dd($d1->diffInMonths($d2));
Upvotes: 1