Skip to content

Commit

Permalink
Merge pull request #42 from hughgrigg/timezone-test
Browse files Browse the repository at this point in the history
Test and fix rounding in timezones
  • Loading branch information
hughgrigg authored Nov 11, 2018
2 parents 578f9c2 + 34be378 commit 1e3bff0
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 49 deletions.
53 changes: 43 additions & 10 deletions src/BusinessTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -406,11 +406,22 @@ public function endOfBusinessDay(): self
*/
public function floor(DateInterval $precision = null): self
{
$seconds = Interval::instance($precision ?: $this->precision())
->inSeconds();
$precisionSeconds = Interval::instance($precision ?: $this->precision())
->inSeconds();

// Allow for sub-hour timezone differences:
// Add the timezone remainder, floor, then take the remainder back off.
$timezoneOffset = $this->getTimezone()->getOffset(new Carbon());
$timezoneRemainder = $timezoneOffset % 3600;

return $this->copy()->setTimestamp(
(int) (floor($this->timestamp / $seconds) * $seconds)
(int) (
floor(
(
$this->timestamp + $timezoneRemainder
) / $precisionSeconds
) * $precisionSeconds
) - $timezoneRemainder
);
}

Expand All @@ -425,11 +436,22 @@ public function floor(DateInterval $precision = null): self
*/
public function round(DateInterval $precision = null): self
{
$seconds = Interval::instance($precision ?: $this->precision())
->inSeconds();
$precisionSeconds = Interval::instance($precision ?: $this->precision())
->inSeconds();

// Allow for sub-hour timezone differences:
// Add the timezone remainder, round, then take the remainder back off.
$timezoneOffset = $this->getTimezone()->getOffset(new Carbon());
$timezoneRemainder = $timezoneOffset % 3600;

return $this->copy()->setTimestamp(
(int) (round($this->timestamp / $seconds) * $seconds)
(int) (
round(
(
$this->timestamp + $timezoneRemainder
) / $precisionSeconds
) * $precisionSeconds
) - $timezoneRemainder
);
}

Expand All @@ -448,10 +470,21 @@ public function round(DateInterval $precision = null): self
public function ceil(DateInterval $precision = null): self
{
$seconds = Interval::instance($precision ?: $this->precision())
->inSeconds();
->inSeconds();

// Allow for sub-hour timezone differences:
// Add the timezone remainder, ceil, then take the remainder back off.
$timezoneOffset = $this->getTimezone()->getOffset(new Carbon());
$timezoneRemainder = $timezoneOffset % 3600;

return $this->copy()->setTimestamp(
(int) (ceil($this->timestamp / $seconds) * $seconds)
(int) (
ceil(
(
$this->timestamp + $timezoneRemainder
) / $seconds
) * $seconds
) - $timezoneRemainder
);
}

Expand Down Expand Up @@ -522,8 +555,8 @@ public function determineLengthOfBusinessDay(

return $this->setLengthOfBusinessDay(
$this->copy()
->setTimestamp($typicalDay->startOfDay()->getTimestamp())
->diffBusiness($typicalDay->endOfDay())
->setTimestamp($typicalDay->startOfDay()->getTimestamp())
->diffBusiness($typicalDay->endOfDay())
);
}

Expand Down
70 changes: 40 additions & 30 deletions tests/Unit/BusinessTime/LengthOfBusinessDayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ public function testLengthOfBusinessDayDefault()
$time = new BusinessTime();

// Then the length of a business day should be 8 hours.
self::assertSame(
'8 hours',
$time->lengthOfBusinessDay()->forHumans()
self::assertEquals(
8,
$time->lengthOfBusinessDay()->inHours(),
'Should be 8 hours',
2
);
self::assertEquals(
480,
$time->lengthOfBusinessDay()->inMinutes(),
'Should be 480 minutes',
2
);
self::assertEquals(8, $time->lengthOfBusinessDay()->inHours());
self::assertEquals(480, $time->lengthOfBusinessDay()->inMinutes());
}

/**
Expand All @@ -39,11 +45,11 @@ public function testLengthOfBusinessDayDefault()
* @dataProvider lengthOfBusinessDayProvider
*
* @param Interval $length
* @param string $expectedDescription
* @param int $expectedSeconds
*/
public function testSetLengthOfBusinessDay(
Interval $length,
string $expectedDescription
int $expectedSeconds
) {
// Given we have a business time;
$time = new BusinessTime();
Expand All @@ -52,9 +58,11 @@ public function testSetLengthOfBusinessDay(
$time->setLengthOfBusinessDay($length);

// Then the length of the business day should be adjusted.
self::assertSame(
$expectedDescription,
$time->lengthOfBusinessDay()->forHumans()
self::assertEquals(
$expectedSeconds,
$time->lengthOfBusinessDay()->inSeconds(),
"Should be ${expectedSeconds}",
2
);
}

Expand All @@ -66,12 +74,12 @@ public function testSetLengthOfBusinessDay(
public function lengthOfBusinessDayProvider(): array
{
return [
[Interval::hour(), '1 hour'],
[Interval::hours(2), '2 hours'],
[Interval::hours(6), '6 hours'],
[Interval::hours(18), '18 hours'],
[Interval::minutes((8 * 60) + 30), '8 hours 30 minutes'],
[Interval::minutes((6 * 60) + 59), '6 hours 59 minutes'],
[Interval::hour(), 60 * 60],
[Interval::hours(2), 2 * 60 * 60],
[Interval::hours(6), 6 * 60 * 60],
[Interval::hours(18), 18 * 60 * 60],
[Interval::minutes((8 * 60) + 30), 8.5 * 60 * 60],
[Interval::minutes((6 * 60) + 59), (6 * 60 * 60) + (59 * 60)],
];
}

Expand All @@ -82,11 +90,11 @@ public function lengthOfBusinessDayProvider(): array
* @dataProvider determineLengthOfBusinessDayProvider
*
* @param BusinessTimeConstraint $constraint
* @param string $expectedDescription
* @param int $expectedSeconds
*/
public function testDetermineLengthOfBusinessDay(
BusinessTimeConstraint $constraint,
string $expectedDescription
int $expectedSeconds
) {
// Given we have a business time with certain constraints;
$time = new BusinessTime();
Expand All @@ -96,9 +104,11 @@ public function testDetermineLengthOfBusinessDay(
$time->determineLengthOfBusinessDay();

// Then the determined length of a business day should be as expected.
self::assertSame(
$expectedDescription,
$time->lengthOfBusinessDay()->forHumans()
self::assertEquals(
$expectedSeconds,
$time->lengthOfBusinessDay()->inSeconds(),
"Should be {$expectedSeconds}",
2
);
}

Expand All @@ -111,32 +121,32 @@ public function testDetermineLengthOfBusinessDay(
public function determineLengthOfBusinessDayProvider(): array
{
return [
[new BetweenHoursOfDay(9, 17), '8 hours'],
[new BetweenHoursOfDay(9, 12), '3 hours'],
[new BetweenHoursOfDay(8, 18), '10 hours'],
[new BetweenHoursOfDay(0, 23), '23 hours'],
[new BetweenHoursOfDay(0, 24), '1 day'],
[new WeekDays(), '1 day'],
[new BetweenHoursOfDay(9, 17), 8 * 60 * 60],
[new BetweenHoursOfDay(9, 12), 3 * 60 * 60],
[new BetweenHoursOfDay(8, 18), 10 * 60 * 60],
[new BetweenHoursOfDay(0, 23), 23 * 60 * 60],
[new BetweenHoursOfDay(0, 24), 24 * 60 * 60],
[new WeekDays(), 24 * 60 * 60],
[
new All(
new WeekDays(),
new BetweenHoursOfDay(9, 17)
),
'8 hours',
8 * 60 * 60,
],
[
// Exclude lunch time.
(new BetweenHoursOfDay(9, 17))->except(
new BetweenHoursOfDay(13, 14)
),
'7 hours',
7 * 60 * 60,
],
[
// Multiple periods.
(new BetweenHoursOfDay(8, 10))
->orAlternatively(new BetweenHoursOfDay(12, 14))
->orAlternatively(new BetweenHoursOfDay(16, 18)),
'6 hours',
6 * 60 * 60,
],
];
}
Expand Down
27 changes: 18 additions & 9 deletions tests/Unit/BusinessTime/PrecisionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ public function testPrecisionDefault()
$time = new BusinessTime();

// Then the precision should be 1 hour.
self::assertSame('1 hour', $time->precision()->forHumans());
self::assertSame(1.0, $time->precision()->inHours());
self::assertEquals(
1.0,
$time->precision()->inHours(),
'Should be 1 hour',
2
);
}

/**
Expand All @@ -31,11 +35,11 @@ public function testPrecisionDefault()
* @dataProvider setPrecisionProvider
*
* @param DateInterval $precision
* @param string $expectedDescription
* @param int $expectedSeconds
*/
public function testSetPrecision(
DateInterval $precision,
string $expectedDescription
int $expectedSeconds
) {
// Given we have a business time instance;
$time = new BusinessTime();
Expand All @@ -44,7 +48,12 @@ public function testSetPrecision(
$time->setPrecision($precision);

// Then the precision should be as expected.
self::assertSame($expectedDescription, $time->precision()->forHumans());
self::assertEquals(
$expectedSeconds,
$time->precision()->inSeconds(),
"Should be {$expectedSeconds} seconds",
2
);
}

/**
Expand All @@ -53,10 +62,10 @@ public function testSetPrecision(
public function setPrecisionProvider(): array
{
return [
[Interval::second(), '1 second'],
[Interval::minute(), '1 minute'],
[Interval::seconds(90), '1 minute 30 seconds'],
[Interval::hour(), '1 hour'],
[Interval::second(), 1],
[Interval::minute(), 60],
[Interval::seconds(90), 90],
[Interval::hour(), 3600],
];
}

Expand Down
Loading

0 comments on commit 1e3bff0

Please sign in to comment.