Skip to content

Breaking Change – Carbon’s diffIn* functions under v3.x

I’ve been starting the process of testing our application at work on the latest version of the Laravel framework. Version 11 came out last month. I used Laravel Shift to migrate the code base from 10.x to 11.x, which saved a lot of time.

When it was done, however, I had several tests that weren’t passing related to date calculations in our code. Errors like this one:

1) Tests\Unit\Helpers\DateHelper::test_days_remaining
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'2'
+'-2'

The Cause

Carbon 3.x includes a changes made in the ♻️ Cleanup diffIn* diffInReal* floatDiffIn* floatDiffInReal* pull request that convert the return value to a float. This has something to do with a bug with DST calculation. This also seems to have resulted in positive return values becoming negative values.

This is a known breaking change in the Carbon library. It just tripped me up since in my case Carbon was updated by upgrading Laravel. I wasn’t specifically thinking of “What changed in Carbon?”

Affected Methods

The following methods in Carbon are affected:

  • diffInDays
  • diffInDaysFiltered
  • diffInHours
  • diffInHoursFiltered
  • diffInMicroseconds
  • diffInMilliseconds
  • diffInMinutes
  • diffInMonths
  • diffInQuarters
  • diffInSeconds
  • diffInUnit
  • diffInWeekdays
  • diffInWeekendDays
  • diffInWeeks
  • diffInYears

Finding these functions in your code

Thank you to the author of the PR, kylekatarnls, for providing the RegEx to search for in your code.

If your IDE supports searching by RegEx, use this to find all instances of the affected functions:

->diffIn[a-zA-Z]+\(

Solution

You can roll back to Carbon 2.0 as long as you don’t have any other packages that require Carbon 3. The Laravel Framework will still work on Carbon 2.x:

"nesbot/carbon": "^2.72",

In order to use Carbon 2.x in your application, add this to your composer.json file and run composer update to downgrade to 2.x

Solution

Each of the affected functions accepts a second parameter, $absolute, that is defaulted to false. You also need to cast the float to an int with (int). Doing both of these things, you’ll get the same result you did in Carbon 2.7.x.

Example:

$startDate->diffInDays(Carbon::now());

//Becomes: 

(int) $startDate->diffInDays(Carbon::now(), true);

Solution

I’ll quote the author of the PR:

It might also be a good occasion to review those calls and wonder “what if date in parameter is before the date on which the method is called?” and re-assert your code is correctly handling the case.

For instance if you have $value = $date->diffInHours($other) and $other is always before $date, then the relevant thing to do instead of using the absolute: true flag is rather to just take the opposite value: $value = - $date->diffInHours($other) or to flip them if $other is also a Carbon object: $value = $other->diffInHours($date) it will clear ambiguity.

kylekatarnis

Conclusion

The biggest takeaway from this exercise was the value in having a solid test coverage that caught this breaking change. Write your tests, folks!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.