1<?php
2
3
4namespace ComboStrap;
5
6
7use DateTime;
8
9
10/**
11 * Class Is8601Date
12 * @package ComboStrap
13 * Format used by Google, Sqlite and others
14 *
15 * This is the date class of Combostrap
16 * that takes a valid input string
17 * and output an iso string
18 */
19class Iso8601Date
20{
21    public const CANONICAL = "date";
22    /**
23     * @var DateTime|false
24     */
25    private $dateTime;
26
27    /**
28     * ATOM = IS08601
29     * See {@link Iso8601Date::getFormat()} for more information
30     */
31    private const VALID_FORMATS = [
32        \DateTimeInterface::ATOM,
33        'Y-m-d H:i:sP',
34        'Y-m-d H:i:s',
35        'Y-m-d H:i',
36        'Y-m-d H',
37        'Y-m-d',
38    ];
39
40
41    /**
42     * Date constructor.
43     */
44    public function __construct($dateTime = null)
45    {
46
47        if ($dateTime == null) {
48
49            $this->dateTime = new DateTime();
50
51        } else {
52
53            $this->dateTime = $dateTime;
54
55        }
56
57    }
58
59    /**
60     * @param null $dateString
61     * @return Iso8601Date
62     * @throws ExceptionCombo if the format is not supported
63     */
64    public static function createFromString($dateString = null): Iso8601Date
65    {
66
67        $original = $dateString;
68
69        if ($dateString === null) {
70            return new Iso8601Date();
71        }
72
73        /**
74         * Time ?
75         * (ie only YYYY-MM-DD)
76         */
77        if (strlen($dateString) <= 10) {
78            /**
79             * We had the time to 00:00:00
80             * because {@link DateTime::createFromFormat} with a format of
81             * Y-m-d will be using the actual time otherwise
82             *
83             */
84            $dateString .= "T00:00:00";
85        }
86
87        /**
88         * Space as T
89         */
90        $dateString = str_replace(" ", "T", $dateString);
91
92
93        if (strlen($dateString) <= 13) {
94            /**
95             * We had the time to 00:00:00
96             * because {@link DateTime::createFromFormat} with a format of
97             * Y-m-d will be using the actual time otherwise
98             *
99             */
100            $dateString .= ":00:00";
101        }
102
103        if (strlen($dateString) <= 16) {
104            /**
105             * We had the time to 00:00:00
106             * because {@link DateTime::createFromFormat} with a format of
107             * Y-m-d will be using the actual time otherwise
108             *
109             */
110            $dateString .= ":00";
111        }
112
113        /**
114         * Timezone
115         */
116        if (strlen($dateString) <= 19) {
117            /**
118             * Because this text metadata may be used in other part of the application
119             * We add the timezone to make it whole
120             * And to have a consistent value
121             */
122            $dateString .= date('P');
123        }
124
125
126        $dateTime = DateTime::createFromFormat(self::getFormat(), $dateString);
127        if ($dateTime === false) {
128            $message = "The date string ($original) is not in a valid date format. (" . join(", ", self::VALID_FORMATS) . ")";
129            throw new ExceptionCombo($message, self::CANONICAL);
130        }
131        return new Iso8601Date($dateTime);
132
133    }
134
135    public static function createFromTimestamp($timestamp): Iso8601Date
136    {
137        $dateTime = new DateTime();
138        $dateTime->setTimestamp($timestamp);
139        return new Iso8601Date($dateTime);
140    }
141
142    /**
143     * And note {@link DATE_ISO8601}
144     * because it's not the compliant IS0-8601 format
145     * as explained here
146     * https://www.php.net/manual/en/class.datetimeinterface.php#datetime.constants.iso8601
147     * ATOM is
148     *
149     * This format is used by Sqlite, Google and is pretty the standard everywhere
150     * https://www.w3.org/TR/NOTE-datetime
151     */
152    public static function getFormat(): string
153    {
154        return DATE_ATOM;
155    }
156
157    public static function isValid($value): bool
158    {
159        $dateObject = Iso8601Date::createFromString($value);
160        return $dateObject->isValidDateEntry();
161    }
162
163    public function isValidDateEntry(): bool
164    {
165        if ($this->dateTime !== false) {
166            return true;
167        } else {
168            return false;
169        }
170    }
171
172    public static function createFromDateTime(DateTime $dateTime): Iso8601Date
173    {
174        return new Iso8601Date($dateTime);
175    }
176
177    public static function createFromNow(): Iso8601Date
178    {
179        return new Iso8601Date();
180    }
181
182    public function getDateTime()
183    {
184        return $this->dateTime;
185    }
186
187    public function __toString()
188    {
189        return $this->getDateTime()->format(self::getFormat());
190    }
191
192    /**
193     * Shortcut to {@link DateTime::format()}
194     * @param $string
195     * @return string
196     * @link https://php.net/manual/en/datetime.format.php
197     */
198    public function format($string): string
199    {
200        return $this->getDateTime()->format($string);
201    }
202
203    public function toString()
204    {
205        return $this->__toString();
206    }
207
208
209
210
211}
212