From aa666d616bddec8be6f97d3c8c392e76dc9beddd Mon Sep 17 00:00:00 2001 From: Austen McDonald Date: Fri, 15 Apr 2016 23:04:06 -0700 Subject: [PATCH] Add TimeKeeper and associated tests. closes #6 --- phpunit.xml | 3 + src/TimeKeeper.php | 105 +++++++++++++++++++++++++++ tests/TimeKeeperTest.php | 152 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 src/TimeKeeper.php create mode 100644 tests/TimeKeeperTest.php diff --git a/phpunit.xml b/phpunit.xml index 4d37631..78aa5f8 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -3,5 +3,8 @@ tests/Models + + tests/TimeKeeperTest.php + diff --git a/src/TimeKeeper.php b/src/TimeKeeper.php new file mode 100644 index 0000000..cc4a1e8 --- /dev/null +++ b/src/TimeKeeper.php @@ -0,0 +1,105 @@ +adjustedEpoch = $gameEpochCopy->add( + $this->interval(0, 0, 0, 0, $gameOffsetSeconds) + ); + $this->theBeginning = new \DateTime("0000-01-01 UTC"); + + $this->secondsPerGameDay = (float) $this->secondsPerDay / $gameDaysPerDay; + $this->secondsPerGameYear = $this->secondsPerGameDay * 365; + $this->secondsPerGameHour = $this->secondsPerGameDay / 24; + $this->secondsPerGameMinute = $this->secondsPerGameHour / 60; + $this->secondsPerGameSecond = $this->secondsPerGameMinute / 60; + } + + public function isNewDay(DateTime $lastInteractionTime): bool { + if ($lastInteractionTime == null) { + return true; + } + $t1 = $this->gameTime(); + $t2 = $this->convertToGameTime($lastInteractionTime); + $d1 = $t1->format("Y-m-d"); + $d2 = $t2->format("Y-m-d"); + + return $d1 != $d2; + } + + public function gameTime(): \DateTime { + return $this->convertToGameTime(new \DateTime()); + } + + public function convertFromGameTime( + \DateTime $time + ): \DateTime { + // Game dates are in the distant past, better not use getTimestamp(). + $i = $this->theBeginning->diff($time); + + $seconds = 0; + $seconds += $i->days * $this->secondsPerGameDay; + $seconds += $i->h * $this->secondsPerGameHour; + $seconds += $i->i * $this->secondsPerGameMinute; + $seconds += $i->s * $this->secondsPerGameSecond; + + $ret = clone($this->adjustedEpoch); + return $ret->add($this->interval(0, 0, 0, 0, (int) $seconds)); + } + + public function convertToGameTime( + \DateTime $time + ): \DateTime { + $timeUnix = $time->getTimestamp(); + $epochUnix = $this->adjustedEpoch->getTimestamp(); + + $interval = $timeUnix - $epochUnix; + + $years = (int) ($interval / $this->secondsPerGameYear); + $interval -= $years * $this->secondsPerGameYear; + + $days = (int) ($interval / $this->secondsPerGameDay); + $interval -= $days * $this->secondsPerGameDay; + + $hours = (int) ($interval / $this->secondsPerGameHour); + $interval -= $hours * $this->secondsPerGameHour; + + $minutes = (int) ($interval / $this->secondsPerGameMinute); + $interval -= $minutes * $this->secondsPerGameMinute; + + $seconds = (int) ($interval / $this->secondsPerGameSecond); + $interval -= $seconds * $this->secondsPerGameSecond; + + $ret = clone($this->theBeginning); + return $ret->add( + $this->interval($years, $days, $hours, $minutes, $seconds) + ); + } + + private function interval( + int $years, + int $days, + int $hours, + int $minutes, + int $seconds + ): \DateInterval { + return new \DateInterval( + 'P'.$years.'Y'.$days.'DT'.$hours.'H'.$minutes.'M'.$seconds.'S' + ); + } +} diff --git a/tests/TimeKeeperTest.php b/tests/TimeKeeperTest.php new file mode 100644 index 0000000..0ff20c0 --- /dev/null +++ b/tests/TimeKeeperTest.php @@ -0,0 +1,152 @@ +gameEpoch = new \DateTime('2015-07-27 00:00:00 PDT');; + $this->gameOffsetSeconds = 0; + $this->gameDaysPerDay = 2; + } + + public function testConvertToBasicConversion() { + $this->gameDaysPerDay = 1; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $date = new \DateTime('2015-07-27 23:59:59 PDT'); + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-01 23:59:59', $converted->format('Y-m-d H:i:s')); + + $date = new \DateTime('2015-07-27 12:00:00 PDT'); + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-01 12:00:00', $converted->format('Y-m-d H:i:s')); + } + + public function testConvertToRespectsGameDaysPerDayUpperBound() { + $date = new \DateTime('2015-07-27 05:59:59 PDT'); + + $this->gameDaysPerDay = 4; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-01', $converted->format('Y-m-d')); + } + + public function testConvertToRespectsGameDaysPerDayNextDay() { + $date = new \DateTime('2015-07-27 06:00:00 PDT'); + + $this->gameDaysPerDay = 4; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-02', $converted->format('Y-m-d')); + } + + public function testConvertToRespectsGameDaysPerDayNextDayUpperBound() { + $date = new \DateTime('2015-07-27 11:59:59 PDT'); + + $this->gameDaysPerDay = 4; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-02', $converted->format('Y-m-d')); + } + + public function testDetectsNewDay() { + } + + public function testConvertToRespectsGameOffset() { + $date = new \DateTime('2015-07-27 01:01:15 PDT'); + + $this->gameOffsetSeconds = 60*60; + $this->gameDaysPerDay = 1; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-01 00:01:15', $converted->format('Y-m-d H:i:s')); + } + + public function testConvertToRespectsGameOffsetUpperBound() { + $date = new \DateTime('2015-07-28 00:59:59 PDT'); + + $this->gameOffsetSeconds = 60*60; + $this->gameDaysPerDay = 1; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-01 23:59:59', $converted->format('Y-m-d H:i:s')); + } + + public function testConvertToRespectsGameOffsetNextDay() { + $date = new \DateTime('2015-07-28 01:00:00 PDT'); + + $this->gameOffsetSeconds = 60*60; + $this->gameDaysPerDay = 1; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-02', $converted->format('Y-m-d')); + } + + public function testConvertToRespectsGameOffsetNextDayUpperBound() { + $date = new \DateTime('2015-07-29 00:59:59 PDT'); + + $this->gameOffsetSeconds = 60*60; + $this->gameDaysPerDay = 1; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertToGameTime($date); + $this->assertEquals('0000-01-02', $converted->format('Y-m-d')); + } + + public function testConvertFromBasicConversion() { + $date = new \DateTime('0000-01-02 00:00:00 UTC'); + + $this->gameDaysPerDay = 1; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertFromGameTime($date); + $this->assertEquals("2015-07-28", $converted->format('Y-m-d')); + } + + public function testConvertFromRespectsGameOffsetNextDay() { + $epoch = new \DateTime('2015-07-27 00:00:00 PDT'); + $date = new \DateTime('0000-01-02 23:59:59 UTC'); + + $this->gameEpoch = $epoch; + $this->gameOffsetSeconds = 60*60; + $this->gameDaysPerDay = 1; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertFromGameTime($date); + $this->assertEquals("2015-07-29 00:59:59", $converted->format('Y-m-d H:i:s')); + } + + public function testConvertFromRespectsGameDaysPerDayNextDay() { + $epoch = new \DateTime('2015-07-27 00:00:00 PDT'); + $date = new \DateTime('0000-01-02 23:59:59 UTC'); + + $this->gameEpoch = $epoch; + $this->gameDaysPerDay = 4; + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + + $converted = $keeper->convertFromGameTime($date); + $this->assertEquals("2015-07-27 11:59:59", $converted->format('Y-m-d H:i:s')); + } + + public function testGameTimeSanity() { + $keeper = new TimeKeeper($this->gameEpoch, $this->gameOffsetSeconds, $this->gameDaysPerDay); + $this->assertNotNull($keeper->gameTime()); + } +}