Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
69.39% covered (warning)
69.39%
34 / 49
46.15% covered (danger)
46.15%
6 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Utc
69.39% covered (warning)
69.39%
34 / 49
46.15% covered (danger)
46.15%
6 / 13
33.65
0.00% covered (danger)
0.00%
0 / 1
 getEmpty
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTimezone
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createDateTime
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 tryParseCore
92.59% covered (success)
92.59%
25 / 27
0.00% covered (danger)
0.00%
0 / 1
5.01
 tryParse
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 tryParseDateTime
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 parse
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 parseDateTime
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toEditableDateTimeFromUnixTime
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 toDateTimeFromUnixTime
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core;
6
7use DateTime;
8use DateTimeImmutable;
9use DateTimeInterface;
10use DateTimeZone;
11use PeServer\Core\Throws\DateTimeException;
12use PeServer\Core\Throws\ParseException;
13
14/**
15 * UTCの生成・読み込み処理
16 *
17 * UTC扱うのにすっげー遠回りしたぞ。
18 */
19abstract class Utc
20{
21    #region define
22
23    private const UTC_FORMAT_01 = 'Y-m-d\TH:i:s.u\Z';
24    private const UTC_FORMAT_02 = 'Y-m-d\TH:i:s\Z';
25    private const UTC_FORMAT_03 = 'Y-m-d\TH:i:s.u';
26    private const UTC_FORMAT_04 = 'Y-m-d\TH:i:s';
27
28    private const UTC_FORMAT_11 = 'Y-m-d H:i:s.u\Z';
29    private const UTC_FORMAT_12 = 'Y-m-d H:i:s\Z';
30    private const UTC_FORMAT_13 = 'Y-m-d H:i:s.u';
31    private const UTC_FORMAT_14 = 'Y-m-d H:i:s';
32
33    private const UTC_FORMAT_21 = 'Y/m/d H:i:s.u\Z';
34    private const UTC_FORMAT_22 = 'Y/m/d H:i:s\Z';
35    private const UTC_FORMAT_23 = 'Y/m/d H:i:s.u';
36    private const UTC_FORMAT_24 = 'Y/m/d H:i:s';
37
38    #endregion
39
40    #region variable
41
42    private static ?DateTimeZone $timezone = null;
43    private static ?DateTimeInterface $empty = null;
44
45    #endregion
46
47    #region function
48
49    public static function getEmpty(): DateTimeInterface
50    {
51        return self::$empty ??= new DateTime('0001-01-01T00:00:00Z');
52    }
53
54    /**
55     * タイムゾーン取得。
56     *
57     * @return DateTimeZone
58     */
59    public static function getTimezone(): DateTimeZone
60    {
61        return self::$timezone ??= new DateTimeZone('UTC');
62    }
63
64    /**
65     * 現在時刻を取得。
66     *
67     * @return DateTimeImmutable
68     */
69    public static function create(): DateTimeImmutable
70    {
71        return new DateTimeImmutable('now', self::getTimezone());
72    }
73
74    /**
75     * 現在時刻を変更可能なオブジェクトとして取得。
76     *
77     * @return DateTime
78     */
79    public static function createDateTime(): DateTime
80    {
81        return new DateTime('now', self::getTimezone());
82    }
83
84    /**
85     * パース処理。
86     *
87     * @param class-string $dateTimeClassName
88     * @phpstan-param class-string<DateTimeImmutable|DateTime> $dateTimeClassName
89     * @param string|null $s
90     * @param DateTimeImmutable|DateTime|null $result
91     * @return boolean
92     * @phpstan-assert-if-true DateTimeImmutable|DateTime $result
93     * @phpstan-assert-if-false null $result
94     */
95    private static function tryParseCore(string $dateTimeClassName, ?string $s, DateTimeImmutable|DateTime|null &$result): bool
96    {
97        if ($s === null) {
98            return false;
99        }
100
101        $formats = [
102            DateTimeInterface::ISO8601_EXPANDED,
103            self::UTC_FORMAT_01,
104            self::UTC_FORMAT_02,
105            self::UTC_FORMAT_03,
106            self::UTC_FORMAT_04,
107            self::UTC_FORMAT_11,
108            self::UTC_FORMAT_12,
109            self::UTC_FORMAT_13,
110            self::UTC_FORMAT_14,
111            self::UTC_FORMAT_21,
112            self::UTC_FORMAT_22,
113            self::UTC_FORMAT_23,
114            self::UTC_FORMAT_24,
115        ];
116
117        $datetime = false;
118        foreach ($formats as $format) {
119            $datetime = $dateTimeClassName::createFromFormat($format, $s, self::getTimezone());
120            if ($datetime !== false) {
121                break;
122            }
123        }
124        if ($datetime === false) {
125            $result = null;
126            return false;
127        }
128
129        $result = $datetime;
130        return true;
131    }
132
133    /**
134     * パース処理。
135     *
136     * @param string|null $s
137     * @param DateTimeImmutable|null $result
138     * @return boolean パース成功状態。
139     * @phpstan-assert-if-true DateTimeImmutable $result
140     * @phpstan-assert-if-false null $result
141     */
142    public static function tryParse(?string $s, ?DateTimeImmutable &$result): bool
143    {
144        //@phpstan-ignore-next-line [TIME]
145        return self::tryParseCore(DateTimeImmutable::class, $s, $result);
146    }
147
148    /**
149     * 変更可能なオブジェクトとしてパース処理。
150     *
151     * @param string|null $s
152     * @param-out DateTime $result
153     * @return boolean パース成功状態。
154     */
155    public static function tryParseDateTime(?string $s, ?DateTime &$result): bool
156    {
157        //@phpstan-ignore-next-line [TIME]
158        return self::tryParseCore(DateTime::class, $s, $result);
159    }
160
161    /**
162     * パース処理。
163     *
164     * @param string $s
165     * @return DateTimeImmutable
166     * @throws ParseException
167     */
168    public static function parse(string $s): DateTimeImmutable
169    {
170        if (self::tryParse($s, $result)) {
171            return $result;
172        }
173
174        throw new ParseException();
175    }
176
177    /**
178     * 変更可能なオブジェクトとしてパース処理。
179     *
180     * @param string $s
181     * @return DateTime
182     * @throws ParseException
183     */
184    public static function parseDateTime(string $s): DateTime
185    {
186        if (self::tryParseDateTime($s, $result)) {
187            return $result;
188        }
189
190        throw new ParseException();
191    }
192
193    /**
194     * 文字列化。
195     *
196     * @param DateTime|DateTimeImmutable|DateTimeInterface $datetime
197     * @return string
198     */
199    public static function toString(DateTime|DateTimeImmutable|DateTimeInterface $datetime): string
200    {
201        return $datetime->format(self::UTC_FORMAT_01);
202    }
203
204    /**
205     * 現在日時を文字列化。
206     *
207     * @return string
208     */
209    public static function createString(): string
210    {
211        return self::toString(self::create());
212    }
213
214    /**
215     * UNIX時間からDateTimeに変換。
216     *
217     * @param int $unixTime
218     * @return DateTime
219     * @throws DateTimeException
220     */
221    public static function toEditableDateTimeFromUnixTime(int $unixTime): DateTime
222    {
223        $result = DateTime::createFromFormat('U', (string)$unixTime, self::getTimezone());
224        if ($result === false) {
225            throw new DateTimeException();
226        }
227
228        return $result;
229    }
230
231    /**
232     * UNIX時間からDateTimeImmutableに変換。・
233     *
234     * @param int $unixTime
235     * @return DateTimeImmutable
236     * @throws DateTimeException
237     */
238    public static function toDateTimeFromUnixTime(int $unixTime): DateTimeImmutable
239    {
240        $result = DateTimeImmutable::createFromFormat('U', (string)$unixTime, self::getTimezone());
241        if ($result === false) {
242            throw new DateTimeException();
243        }
244
245        return $result;
246    }
247
248    #endregion
249}