Date::isGt()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stadly\Http\Header\Value;
6
7
use DateTime;
8
use DateTimeImmutable;
9
use DateTimeInterface;
10
use DateTimeZone;
11
use InvalidArgumentException;
12
use Stadly\Http\Utilities\Rfc7231;
13
14
/**
15
 * Class for handling dates.
16
 *
17
 * Specification: https://tools.ietf.org/html/rfc7231#section-7.1.1.1
18
 */
19
final class Date
20
{
21
    /**
22
     * @var DateTimeImmutable Date.
23
     */
24
    private $date;
25
26
    /**
27
     * @var bool Whether the date is a weak validator.
28
     */
29
    private $isWeak;
30
31
    /**
32
     * Constructor.
33
     *
34
     * @param DateTimeInterface $date Date.
35
     * @param bool $isWeak Whether the date is a weak validator.
36
     */
37 7
    public function __construct(DateTimeInterface $date, bool $isWeak = true)
38
    {
39
        // Discard microseconds.
40 7
        $immutableDate = DateTimeImmutable::createFromFormat('U', $date->format('U'));
41 7
        assert($immutableDate !== false);
42
43 7
        $this->date = $immutableDate->setTimezone(new DateTimeZone('GMT'));
44 7
        $this->isWeak = $isWeak;
45
    }
46
47
    /**
48
     * Construct date from a Unix time timestamp.
49
     *
50
     * @param float $timestamp Unix time timestamp.
51
     * @param bool $isWeak Whether the date is a weak validator.
52
     * @return self Date generated based on the Unix time timestamp.
53
     */
54 8
    public static function fromTimestamp(float $timestamp, bool $isWeak = true): self
55
    {
56 8
        $dateTime = DateTime::createFromFormat('U.u', sprintf('%.6F', $timestamp));
57 8
        assert($dateTime !== false);
58
59 8
        return new self($dateTime, $isWeak);
60
    }
61
62
    /**
63
     * Construct date from string.
64
     *
65
     * @param string $date Date string.
66
     * @param bool $isWeak Whether the date is a weak validator.
67
     * @return self Date generated based on the string.
68
     */
69 18
    public static function fromString(string $date, bool $isWeak = true): self
70
    {
71 18
        $plainDate = mb_convert_encoding($date, 'ISO-8859-1', 'UTF-8');
72 18
        if ($plainDate === $date) {
73 18
            if (preg_match('{^' . Rfc7231::IMF_FIXDATE . '$}', $date) === 1) {
74 2
                $dateTime = DateTime::createFromFormat('D, d M Y H:i:s T', $date);
75 2
                assert($dateTime !== false);
76 2
                return new self($dateTime, $isWeak);
77
            }
78
79 16
            if (preg_match('{^' . Rfc7231::RFC850_DATE . '$}', $date) === 1) {
80 13
                return self::fromRfc850String($date, $isWeak);
81
            }
82
83 3
            if (preg_match('{^' . Rfc7231::ASCTIME_DATE . '$}', $date) === 1) {
84 1
                $dateTime = DateTime::createFromFormat('D M j H:i:s Y', $date, new DateTimeZone('GMT'));
85 1
                assert($dateTime !== false);
86 1
                return new self($dateTime, $isWeak);
87
            }
88
        }
89
90 2
        throw new InvalidArgumentException('Invalid date: ' . $date);
91
    }
92
93 13
    private static function fromRfc850String(string $date, bool $isWeak): self
94
    {
95 13
        $now = new DateTimeImmutable('now', new DateTimeZone('GMT'));
96
97 13
        preg_match('{^' . Rfc7231::RFC850_DATE_CAPTURE . '$}', $date, $matches);
98
99
        // Assume the year belongs to the next century.
100 13
        $year = (1 + (int)substr($now->format('Y'), 0, -2)) . $matches['YEAR'];
101
102 13
        $newDate = sprintf('%s-%s-%s %s', $matches['DAY'], $matches['MONTH'], $year, $matches['TIME_OF_DAY']);
103 13
        $dateTime = DateTime::createFromFormat('d-M-Y H:i:s', $newDate, new DateTimeZone('GMT'));
104 13
        assert($dateTime !== false);
105
106
        // While date is more than 50 years in the future, interpret the date as 100 years earlier.
107 13
        while ($now->modify('+50 years') < $dateTime) {
108 13
            $dateTime->modify('-100 years');
109
        }
110
111 13
        return new self($dateTime, $isWeak);
112
    }
113
114
    /**
115
     * @return string String representation of the date.
116
     */
117 2
    public function __toString(): string
118
    {
119 2
        return $this->date->format('D, d M Y H:i:s T');
120
    }
121
122
    /**
123
     * Specification: https://tools.ietf.org/html/rfc7232#section-2.1
124
     *
125
     * @return bool Whether the date is a weak validator.
126
     */
127 2
    public function isWeak(): bool
128
    {
129 2
        return $this->isWeak;
130
    }
131
132
    /**
133
     * @param self $date Date to compare with.
134
     * @return bool Whether this date is earlier than the date it is compared to.
135
     */
136 3
    public function isLt(self $date): bool
137
    {
138 3
        return $this->date < $date->date;
139
    }
140
141
    /**
142
     * @param self $date Date to compare with.
143
     * @return bool Whether this date is earlier than or the same as the date it is compared to.
144
     */
145 3
    public function isLte(self $date): bool
146
    {
147 3
        return $this->date <= $date->date;
148
    }
149
150
    /**
151
     * @param self $date Date to compare with.
152
     * @return bool Whether this date is the same as the date it is compared to.
153
     */
154 3
    public function isEq(self $date): bool
155
    {
156 3
        $format = DateTimeInterface::RFC3339_EXTENDED;
157 3
        return $this->date->format($format) === $date->date->format($format);
158
    }
159
160
    /**
161
     * @param self $date Date to compare with.
162
     * @return bool Whether this date is later than or the same as the date it is compared to.
163
     */
164 3
    public function isGte(self $date): bool
165
    {
166 3
        return $this->date >= $date->date;
167
    }
168
169
    /**
170
     * @param self $date Date to compare with.
171
     * @return bool Whether this date is later than the date it is compared to.
172
     */
173 3
    public function isGt(self $date): bool
174
    {
175 3
        return $this->date > $date->date;
176
    }
177
}
178