Skip to content

Commit

Permalink
Add date class (#46)
Browse files Browse the repository at this point in the history
* To allow dates to be represented, introduce date class

* To provide testing for the Date class, import unit test

* To complete the import of the Date class into the Clock library, tweak dependnecies, namespacing etc.

* To enable us to use the new Date class, add the ability for a Clock to return a Date object

* Make class final

Co-authored-by: Ben Challis <[email protected]>

Co-authored-by: Zoran Antolović <[email protected]>
Co-authored-by: Ben Challis <[email protected]>
  • Loading branch information
3 people authored Jul 30, 2021
1 parent b1e991b commit f96fd80
Show file tree
Hide file tree
Showing 10 changed files with 597 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/Clock.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ public function now(): \DateTimeImmutable;
* prevent unintended side effects.
*/
public function nowMutable(): \DateTime;

public function today(): Date;
}
148 changes: 148 additions & 0 deletions lib/Date.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php

declare(strict_types=1);

namespace Lendable\Clock;

use Lendable\Clock\Date\InvalidDate;

final class Date
{
private int $year;

private int $month;

private int $day;

private function __construct(int $year, int $month, int $day)
{
if (!checkdate($month, $day, $year)) {
throw InvalidDate::fromDate($year, $month, $day);
}

$this->year = $year;
$this->month = $month;
$this->day = $day;
}

public static function fromYearMonthDay(int $year, int $month, int $day): self
{
return new self($year, $month, $day);
}

public static function fromDateTime(\DateTimeInterface $dateTime): self
{
return new self(
(int) $dateTime->format('Y'),
(int) $dateTime->format('m'),
(int) $dateTime->format('d')
);
}

public static function fromYearMonthDayString(string $value): self
{
$result = preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value, $matches);

if ($result === 0) {
throw new InvalidDate('Failed to parse string as a Y-m-d formatted date.');
}

return self::fromYearMonthDay(
(int) $matches[1],
(int) $matches[2],
(int) $matches[3]
);
}

public static function fromYearsAgo(int $yearsAgo): self
{
$dob = new \DateTimeImmutable("today - $yearsAgo years");

return self::fromDateTime($dob);
}

public function year(): int
{
return $this->year;
}

public function month(): int
{
return $this->month;
}

public function day(): int
{
return $this->day;
}

public function equals(self $other): bool
{
return $this->year === $other->year
&& $this->month === $other->month
&& $this->day === $other->day;
}

public function isBefore(self $other): bool
{
return $this->toDateTime() < $other->toDateTime();
}

public function isBeforeOrEqualTo(self $other): bool
{
return $this->isBefore($other) || $this->equals($other);
}

public function isAfter(self $other): bool
{
return $this->toDateTime() > $other->toDateTime();
}

public function isBetween(self $start, self $end): bool
{
return !$this->isBefore($start) && !$this->isAfter($end);
}

public function toDateTime(): \DateTimeImmutable
{
$dateTime = \DateTimeImmutable::createFromFormat(
'Y-m-d H:i:s',
sprintf('%d-%d-%d 00:00:00', $this->year, $this->month, $this->day),
);
\assert($dateTime instanceof \DateTimeImmutable);

return $dateTime;
}

public function toYearMonthDayString(): string
{
return sprintf('%d-%02d-%02d', $this->year, $this->month, $this->day);
}

public function diff(self $other): \DateInterval
{
return $this->toDateTime()->diff($other->toDateTime());
}

public function differenceInDays(self $other): int
{
return (int) $this->diff($other)->format('%a');
}

public function dayAfter(): self
{
return $this->modify('+1 days');
}

public function dayBefore(): self
{
return $this->modify('-1 days');
}

private function modify(string $modification): self
{
$modified = $this->toDateTime()->modify($modification);

return self::fromDateTime($modified);
}
}
13 changes: 13 additions & 0 deletions lib/Date/InvalidDate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Lendable\Clock\Date;

final class InvalidDate extends \InvalidArgumentException
{
public static function fromDate(int $year, int $month, int $day): self
{
return new self(sprintf('Date %d-%d-%d (Y-m-d) is invalid.', $year, $month, $day));
}
}
5 changes: 5 additions & 0 deletions lib/FixedClock.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ public function changeTimeTo(\DateTimeInterface $time): void
{
$this->now = DateTimeNormalizer::immutable($time);
}

public function today(): Date
{
return Date::fromDateTime($this->now());
}
}
5 changes: 5 additions & 0 deletions lib/PersistedFixedClock.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ public function nowMutable(): \DateTime
return $this->delegate->nowMutable();
}

public function today(): Date
{
return Date::fromDateTime($this->now());
}

public function changeTimeTo(\DateTimeInterface $time): void
{
$this->delegate->changeTimeTo($time);
Expand Down
5 changes: 5 additions & 0 deletions lib/SystemClock.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ public function nowMutable(): \DateTime
{
return \DateTime::createFromImmutable($this->now());
}

public function today(): Date
{
return Date::fromDateTime($this->now());
}
}
Loading

0 comments on commit f96fd80

Please sign in to comment.