Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

yoeriboven's avatar

Compare Carbon without milliseconds

In one of my models I'm casting to a Carbon instance.

protected $dates = [
    'some_date',
];

Here's my test:

public function it_saves_the_correct_datetime()
{
    $user = User::create();

    $this->assertEquals(now()->addDays(14), $user->some_date);
}

This test will fail because the first instance has milliseconds and the instance coming from the database has not.

Failed asserting that two DateTime objects are equal.
--- Expected
+++ Actual
@@ @@
-2020-05-15T15:00:07.305878+0000
+2020-05-15T15:00:07.000000+0000

To fix this I add this at the beginning of the test Carbon::setTestNow(now()->roundSecond()).

Anyone know a better way to compare two Carbon instance to each other without looking at the milliseconds?

0 likes
5 replies
Snapey's avatar

Rounding seems risky as you don't know if it will round up or down.

You could format to the same as your database?

$this->assertEquals(now()->addDays(14)->format('Y-m-d H:i:s'), $user->some_date);

but it seems odd that this should be necessary?

1 like
yoeriboven's avatar

Thought of that but it makes the test a bit ugly and as you said, it's rather strange this happens.

This happens in a package I'm building by the way. Using Orchestra.

tykus's avatar

I would suggest whenever you are testing to use Carbon's setTestNow helper so that you are working with known datetimes rather than begin sensitive to when the test is being executed

public function it_saves_the_correct_datetime()
{
    Carbon\Carbon::setTestNow('2020-05-01 15:00:00');
    $user = User::create();

    $this->assertEquals(now()->addDays(14), $user->some_date);
}

Remember to clean-up in the tearDown method.

If you don't like that, then maybe consider the isSameX methods, choosing X depending on the level of granularity you want:

public function it_saves_the_correct_datetime()
{
    Carbon\Carbon::setTestNow('2020-05-01 15:00:00');
    $user = User::create();

    $this->assertEquals(now()->addDays(14)->isSameSecond($user->some_date));
}

2 likes
click's avatar

Or add your own assertions to the project.

For example you could make your own DateAssertionsTrait add add it to your TestCase.

public function assertSameDay($expected, $actual, $message = null)
{
      $this->assertEquals(
             Carbon::make($actual)->toDateString(),
             Carbon::make($expected)->toDateString(),
             $message
       );
}


public function assertSameDate($expected, $actual, $message = null)
{
      $this->assertEquals(
             Carbon::make($actual)->toDateTimeString(),
             Carbon::make($expected)->toDateTimeString(),
             $message
       );
}

Usage:

$this->assertSameDate(now()->addDays(14), $user->some_date); 
// or
$this->assertSameDate('2020-04-23 00:00:00', $user->some_date);

// or if you don't care about the time: 
$this->assertSameDay('2020-04-23', $user->some_date); 
2 likes
JoshP's avatar

I solved by converting to timestamp, which knows nothing of microseconds...

$this->assertEquals($actual->timestamp, $expected->timestamp);
1 like

Please or to participate in this conversation.