Passed
Push — master ( 680f77...b0ffe1 )
by Mr
01:57
created

Timestamp::equals()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/value-object project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\ValueObject;
10
11
use Daikon\Interop\Assertion;
12
use Daikon\Interop\InvalidArgumentException;
13
use Daikon\Interop\MakeEmptyInterface;
14
use DateTimeImmutable;
15
use DateTimeZone;
16
17
final class Timestamp implements MakeEmptyInterface, ValueObjectInterface
18
{
19
    public const NATIVE_FORMAT = 'Y-m-d\TH:i:s.uP';
20
21
    private ?DateTimeImmutable $value;
22
23
    public static function now(): self
24
    {
25
        return new self(new DateTimeImmutable);
26
    }
27
28
    public static function epoch(): self
29
    {
30
        return new self((new DateTimeImmutable)->setTimestamp(0));
31
    }
32
33
    /** @param int|string $time */
34
    public static function fromTime($time): self
35
    {
36
        Assertion::integerish($time, 'Unix time must be an integer.');
37
        Assertion::greaterOrEqualThan((int)$time, 0, 'Unix time must be greater or equal than 0.');
38
        return new self(new DateTimeImmutable("@$time"));
39
    }
40
41 1
    public static function makeEmpty(): self
42
    {
43 1
        return new self;
44
    }
45
46 1
    public function toTime(): int
47
    {
48 1
        Assertion::false($this->isEmpty(), 'Cannot convert null to time.');
49
        /** @psalm-suppress PossiblyNullReference */
50 1
        return $this->value->getTimestamp();
51
    }
52
53 8
    public static function fromString(string $date, string $format = self::NATIVE_FORMAT): self
54
    {
55 8
        if ($date === 'now') {
56
            return self::now();
57
        }
58
59 8
        if ($date === 'epoch') {
60
            return self::epoch();
61
        }
62
63 8
        if (is_numeric($date)) {
64 1
            $format = strpos($date, '.') ? 'U.u' : 'U';
65
        }
66
67 8
        if (!$dateTime = DateTimeImmutable::createFromFormat($format, $date)) {
68 1
            $time = strtotime($date);
69 1
            if ($time === false || !$dateTime = new DateTimeImmutable('@'.$time)) {
70
                throw new InvalidArgumentException('Invalid date string given to '.self::class);
71
            }
72
        }
73
74 8
        return new self($dateTime);
75
    }
76
77
    /** @param null|int|string $value */
78 8
    public static function fromNative($value): self
79
    {
80 8
        Assertion::nullOrSatisfy(
81 8
            $value,
82
            /** @param mixed $value */
83 8
            fn($value): bool => is_string($value) || is_numeric($value),
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected ':', expecting T_DOUBLE_ARROW on line 83 at column 22
Loading history...
84 8
            'Trying to create Timestamp VO from unsupported value type.'
85
        );
86
87 8
        return empty($value) || $value === 'null' ? new self : self::fromString((string)$value);
88
    }
89
90 6
    public function toNative(): ?string
91
    {
92 6
        return is_null($this->value) ? null : $this->value->format(self::NATIVE_FORMAT);
93
    }
94
95
    /** @param self $comparator */
96 1
    public function equals($comparator): bool
97
    {
98 1
        Assertion::isInstanceOf($comparator, self::class);
99 1
        return $this->toNative() === $comparator->toNative();
100
    }
101
102 5
    public function isEmpty(): bool
103
    {
104 5
        return $this->value === null;
105
    }
106
107 1
    public function isBefore(self $comparand): bool
108
    {
109 1
        if ($this->isEmpty()) {
110 1
            return true;
111 1
        } elseif ($comparand->isEmpty()) {
112 1
            return false;
113
        } else {
114 1
            return $this->value < DateTimeImmutable::createFromFormat(self::NATIVE_FORMAT, (string)$comparand);
115
        }
116
    }
117
118 1
    public function isAfter(self $comparand): bool
119
    {
120 1
        if ($this->isEmpty()) {
121 1
            return false;
122 1
        } elseif ($comparand->isEmpty()) {
123 1
            return true;
124
        } else {
125 1
            return $this->value > DateTimeImmutable::createFromFormat(self::NATIVE_FORMAT, (string)$comparand);
126
        }
127
    }
128
129
    /** @param string $interval */
130 1
    public function modify($interval): self
131
    {
132 1
        Assertion::false($this->isEmpty(), 'Cannot modify null Timestamp.');
133 1
        Assertion::string($interval);
134 1
        Assertion::notEmpty($interval);
135
        /** @psalm-suppress PossiblyNullReference */
136 1
        $modified = $this->value->modify($interval);
137 1
        Assertion::isInstanceOf($modified, DateTimeImmutable::class, 'Invalid modification interval.');
138
139 1
        return new self($modified);
140
    }
141
142 4
    public function __toString(): string
143
    {
144 4
        return $this->toNative() ?? 'null';
145
    }
146
147 8
    private function __construct(DateTimeImmutable $value = null)
148
    {
149 8
        $this->value = $value ? $value->setTimezone(new DateTimeZone('UTC')) : $value;
150 8
    }
151
}
152