Vũ Nhật Anh
Vũ Nhật Anh

Reputation: 512

Incorrect diffInMonths laravel Carbon between Feb 1 and Mar 1

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

Answers (6)

Matthew Bowen
Matthew Bowen

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

Umid Aka
Umid Aka

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

Arun J
Arun J

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

Emad Omar
Emad Omar

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

user6679664
user6679664

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

parastoo
parastoo

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

Related Questions