Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
Record
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
3 / 3
19
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
8
 parseStr
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
10
 toDateTime
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
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
9namespace Selen\DateTime;
10
11use DateTime;
12use ValueError;
13
14/**
15 * 日付情報を保持するクラス
16 */
17class 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}