Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
27 / 27 |
|
100.00% |
3 / 3 |
CRAP | |
100.00% |
1 / 1 |
Record | |
100.00% |
27 / 27 |
|
100.00% |
3 / 3 |
19 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
8 | |||
parseStr | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
10 | |||
toDateTime | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | /** |
4 | * @license MIT |
5 | * @author hazuki3417<hazuki3417@gmail.com> |
6 | * @copyright 2023 hazuki3417 all rights reserved. |
7 | */ |
8 | |
9 | namespace Selen\DateTime; |
10 | |
11 | use DateTime; |
12 | use ValueError; |
13 | |
14 | /** |
15 | * 日付情報を保持するクラス |
16 | */ |
17 | class Record |
18 | { |
19 | /** @var int 年 */ |
20 | public int $year; |
21 | /** @var int 月 */ |
22 | public int $month; |
23 | /** @var int 日 */ |
24 | public int $day; |
25 | /** @var int 時 */ |
26 | public int $hour; |
27 | /** @var int 分 */ |
28 | public int $minute; |
29 | /** @var int 秒 */ |
30 | public int $second; |
31 | |
32 | /** |
33 | * @param int $year 年 |
34 | * @param int $month 月 |
35 | * @param int $day 日 |
36 | * @param int $hour 時 |
37 | * @param int $minute 分 |
38 | * @param int $second 秒 |
39 | */ |
40 | public function __construct( |
41 | int $year = 1, |
42 | int $month = 1, |
43 | int $day = 1, |
44 | int $hour = 0, |
45 | int $minute = 0, |
46 | int $second = 0, |
47 | ) { |
48 | /** |
49 | * NOTE: 無効な日付は許容しないように実装しています。 |
50 | * 下記のクラス・メソッドで日付文字列をパースした場合、値が変換されるケースがあります。 |
51 | * 例)月の最大日数より大きい日付を指定すると月をまたいだ値となる。 |
52 | * new DateTimeImmutable('2001-02-35') |
53 | * -> 2001-03-07 として扱われる |
54 | * DateTime::createFromFormat('Y-m-d', '2001-02-35')) |
55 | * -> 2001-03-07 として扱われる |
56 | * 下記の関数は日付文字列のパースのみを提供する。 |
57 | * date_parse_from_format() |
58 | */ |
59 | $mes = 'Invalid value. Please specify a value of %s or more for $%s.'; |
60 | $this->year = (1 <= $year) ? $year : throw new ValueError(\sprintf($mes, 1, 'year')); |
61 | $this->month = (1 <= $month) ? $month : throw new ValueError(\sprintf($mes, 1, 'month')); |
62 | $this->day = (1 <= $day) ? $day : throw new ValueError(\sprintf($mes, 1, 'day')); |
63 | $this->hour = (0 <= $hour) ? $hour : throw new ValueError(\sprintf($mes, 0, 'hour')); |
64 | $this->minute = (0 <= $minute) ? $minute : throw new ValueError(\sprintf($mes, 0, 'minute')); |
65 | $this->second = (0 <= $second) ? $second : throw new ValueError(\sprintf($mes, 0, 'second')); |
66 | |
67 | if (!\checkdate($this->month, $this->day, $this->year)) { |
68 | throw new ValueError('Invalid Gregorian calendar.'); |
69 | } |
70 | } |
71 | |
72 | /** |
73 | * 日付文字列からインスタンスを生成します |
74 | * |
75 | * @param string $parseFormat パース文字列 |
76 | * @param string $dateTime 日付文字列 |
77 | * |
78 | * @return Record 成功した場合はインスタンスを返します |
79 | */ |
80 | public static function parseStr(string $parseFormat, string $dateTime): Record |
81 | { |
82 | if ($parseFormat === '') { |
83 | throw new ValueError('Invalid value. Please specify format string.'); |
84 | } |
85 | |
86 | if ($dateTime === '') { |
87 | throw new ValueError('Invalid value. Please specify a date string.'); |
88 | } |
89 | |
90 | /** |
91 | * NOTE: 日付の妥当性チェックを行うために下記の関数を利用しています。 |
92 | * - date_parse_from_format() |
93 | * 理由)上記以外のクラス・メソッドで日付文字列をパースした場合、値が変換されるケースがあります。 |
94 | * |
95 | * 例)月の最大日数より大きい日付を指定すると月をまたいだ値となる。 |
96 | * new DateTimeImmutable('2001-02-35') |
97 | * -> 2001-03-07 として扱われる |
98 | * DateTime::createFromFormat('Y-m-d', '2001-02-35')) |
99 | * -> 2001-03-07 として扱われる |
100 | */ |
101 | $result = date_parse_from_format($parseFormat, $dateTime); |
102 | |
103 | if (0 < $result['error_count']) { |
104 | throw new ValueError('Failed to parse. Invalid date format or date string.'); |
105 | } |
106 | |
107 | return new self( |
108 | $result['year'] === false ? 1 : $result['year'], |
109 | $result['month'] === false ? 1 : $result['month'], |
110 | $result['day'] === false ? 1 : $result['day'], |
111 | $result['hour'] === false ? 0 : $result['hour'], |
112 | $result['minute'] === false ? 0 : $result['minute'], |
113 | $result['second'] === false ? 0 : $result['second'], |
114 | ); |
115 | } |
116 | |
117 | /** |
118 | * DateTimeインスタンスを取得します |
119 | * |
120 | * @return DateTime インスタンスを返します |
121 | */ |
122 | public function toDateTime(): DateTime |
123 | { |
124 | return (new DateTime()) |
125 | ->setDate($this->year, $this->month, $this->day) |
126 | ->setTime($this->hour, $this->minute, $this->second); |
127 | } |
128 | } |