From 790f2bc8c560541cc5a12e506195e3df4ee2c862 Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 26 Oct 2018 22:15:03 +0200 Subject: [PATCH] Improve milliseconds/microseconds support (#1486) Fix #1481 total milliseconds/microseconds in intervals Fix #1482 microseconds in intervals add, instance and create --- src/Carbon/CarbonInterval.php | 30 +++++++++++++++++++++--------- tests/AbstractTestCase.php | 7 ++++++- tests/CarbonInterval/AddTest.php | 17 +++++++++++++---- tests/CarbonInterval/TotalTest.php | 7 +++++++ 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/Carbon/CarbonInterval.php b/src/Carbon/CarbonInterval.php index e295b4f2f1..8c83f4d04c 100644 --- a/src/Carbon/CarbonInterval.php +++ b/src/Carbon/CarbonInterval.php @@ -239,7 +239,7 @@ public function __construct($years = 1, $months = null, $weeks = null, $days = n parent::__construct($spec); if (!is_null($microseconds)) { - $this->f = $microseconds; + $this->f = $microseconds / 1000000; } } @@ -339,12 +339,13 @@ public static function getMicrosecondsPerMillisecond() * @param int $hours * @param int $minutes * @param int $seconds + * @param int $microseconds * * @return static */ - public static function create($years = 1, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null) + public static function create($years = 1, $months = null, $weeks = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null) { - return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds); + return new static($years, $months, $weeks, $days, $hours, $minutes, $seconds, $microseconds); } /** @@ -571,7 +572,11 @@ public static function fromString($intervalDefinition) */ public static function instance(DateInterval $di) { + $microseconds = $di->f; $instance = new static(static::getDateIntervalSpec($di)); + if ($microseconds) { + $instance->f = $microseconds; + } $instance->invert = $di->invert; foreach (['y', 'm', 'd', 'h', 'i', 's'] as $unit) { if ($di->$unit < 0) { @@ -677,11 +682,11 @@ public function __get($name) case 'milli': case 'milliseconds': - return (int) floor($this->f / 1000); + return (int) floor(round($this->f * 1000000) / 1000); case 'micro': case 'microseconds': - return (int) $this->f; + return (int) round($this->f * 1000000); case 'weeks': return (int) floor($this->d / static::getDaysPerWeek()); @@ -739,12 +744,12 @@ public function __set($name, $value) case 'milli': case 'millisecond': - $this->f = $value * 1000 + $this->f % 1000; + $this->microseconds = $value * 1000 + $this->microseconds % 1000; break; case 'micro': case 'microsecond': - $this->f = $value; + $this->f = $value / 1000000; break; default: @@ -1128,6 +1133,7 @@ public function add($unit, $value = 1) $this->hours += $interval->h * $sign; $this->minutes += $interval->i * $sign; $this->seconds += $interval->s * $sign; + $this->microseconds += $interval->microseconds * $sign; return $this; } @@ -1310,7 +1316,7 @@ public function total($unit) if (in_array($unit, ['days', 'weeks'])) { $realUnit = 'dayz'; - } elseif (!in_array($unit, ['seconds', 'minutes', 'hours', 'dayz', 'months', 'years'])) { + } elseif (!in_array($unit, ['microseconds', 'milliseconds', 'seconds', 'minutes', 'hours', 'dayz', 'months', 'years'])) { throw new InvalidArgumentException("Unknown unit '$unit'."); } @@ -1323,7 +1329,13 @@ public function total($unit) if ($source === $realUnit) { $unitFound = true; - $result += $this->$source; + $value = $this->$source; + if ($source === 'microseconds') { + $value %= 1000; + } + if ($source !== 'milliseconds') { + $result += $value; + } $cumulativeFactor = 1; } diff --git a/tests/AbstractTestCase.php b/tests/AbstractTestCase.php index c71a845c02..6a5eba19f7 100644 --- a/tests/AbstractTestCase.php +++ b/tests/AbstractTestCase.php @@ -140,7 +140,7 @@ public function assertInstanceOfCarbon($d) $this->assertInstanceOf(CarbonInterface::class, $d); } - public function assertCarbonInterval(CarbonInterval $ci, $years, $months = null, $days = null, $hours = null, $minutes = null, $seconds = null) + public function assertCarbonInterval(CarbonInterval $ci, $years, $months = null, $days = null, $hours = null, $minutes = null, $seconds = null, $microseconds = null) { $actual = ['years' => $ci->years]; @@ -171,6 +171,11 @@ public function assertCarbonInterval(CarbonInterval $ci, $years, $months = null, $expected['seconds'] = $seconds; } + if ($microseconds !== null) { + $actual['microseconds'] = $ci->microseconds; + $expected['microseconds'] = $microseconds; + } + $this->assertSame($expected, $actual); } diff --git a/tests/CarbonInterval/AddTest.php b/tests/CarbonInterval/AddTest.php index ee4095e6c8..869994c7ab 100644 --- a/tests/CarbonInterval/AddTest.php +++ b/tests/CarbonInterval/AddTest.php @@ -38,6 +38,19 @@ public function testAddWithNegativeDiffDateInterval() $this->assertCarbonInterval($ci, 4, 3, 28, 8, 10, 11); } + public function testAddMicroseconds() + { + $diff = Carbon::now()->diff(Carbon::now()->addDays(3)->addMicroseconds(111222)); + $ci = CarbonInterval::create(1, 0, 0, 2, 0, 0, 0, 222333)->add($diff); + $this->assertCarbonInterval($ci, 1, 0, 5, 0, 0, 0, 333555); + $diff = Carbon::now()->diff(Carbon::now()->addDays(3)); + $ci = CarbonInterval::create(1, 0, 0, 2, 0, 0, 0, 222333)->add($diff); + $this->assertCarbonInterval($ci, 1, 0, 5, 0, 0, 0, 222333); + $diff = Carbon::now()->diff(Carbon::now()->addDays(3)->addMicroseconds(111222)); + $ci = CarbonInterval::create(1, 0, 0, 2, 0, 0, 0)->add($diff); + $this->assertCarbonInterval($ci, 1, 0, 5, 0, 0, 0, 111222); + } + public function testAddWithRawDiffDateInterval() { $diff = (new \DateTime())->diff(new \DateTime('3 weeks')); @@ -52,9 +65,6 @@ public function testAddWithRawNegativeDiffDateInterval() $this->assertCarbonInterval($ci, 4, 3, 28, 8, 10, 11); } - /** - * @group i - */ public function testAddAndSubMultipleFormats() { $this->assertCarbonInterval(CarbonInterval::day()->add('hours', 3), 0, 0, 1, 3, 0, 0); @@ -74,7 +84,6 @@ public function testAddAndSubMultipleFormats() } /** - * @group i * @expectedException \InvalidArgumentException * @expectedExceptionMessage This type of data cannot be added/subtracted. */ diff --git a/tests/CarbonInterval/TotalTest.php b/tests/CarbonInterval/TotalTest.php index c292323b9d..0f487e586f 100644 --- a/tests/CarbonInterval/TotalTest.php +++ b/tests/CarbonInterval/TotalTest.php @@ -51,6 +51,8 @@ public function testGetTotalsViaGetters() { $interval = CarbonInterval::create(0, 0, 0, 0, 150, 0, 0); + $this->assertSame(150 * 60 * 60 * 1000 * 1000, $interval->totalMicroseconds); + $this->assertSame(150 * 60 * 60 * 1000, $interval->totalMilliseconds); $this->assertSame(150 * 60 * 60, $interval->totalSeconds); $this->assertSame(150 * 60, $interval->totalMinutes); $this->assertSame(150, $interval->totalHours); @@ -58,6 +60,11 @@ public function testGetTotalsViaGetters() $this->assertSame(150 / 24 / 7, $interval->totalWeeks); $this->assertSame(150 / 24 / 7 / 4, $interval->totalMonths); $this->assertSame(150 / 24 / 7 / 4 / 12, $interval->totalYears); + + $interval = CarbonInterval::milliseconds(12312); + + $this->assertSame(12312000, $interval->totalMicroseconds); + $this->assertSame(12312, $interval->totalMilliseconds); } public function testGetTotalsViaGettersWithCustomFactors()