99
1010namespace MaplePHP \DTO \Format ;
1111
12+ use DateTime ;
13+ use DateTimeImmutable ;
14+ use DateTimeInterface ;
15+ use DateTimeZone ;
1216use Exception ;
1317use IntlDateFormatter ;
1418use InvalidArgumentException ;
1519
1620final class Clock extends FormatAbstract implements FormatInterface
1721{
1822 static protected ?string $ defaultLocale = 'en ' ;
23+
24+ static protected string |DateTimeZone |null $ defaultTimezone = null ;
25+
1926 protected ?string $ locale = null ;
2027 protected array $ parts = [];
2128
@@ -30,8 +37,11 @@ public function __construct(mixed $value)
3037 if (is_array ($ value ) || is_object ($ value )) {
3138 throw new InvalidArgumentException ("Is expecting a string or a convertable string value. " , 1 );
3239 }
33-
34- parent ::__construct (new \DateTime ($ value ));
40+ $ date = new DateTime ($ value );
41+ if (!is_null (self ::$ defaultTimezone )) {
42+ $ date ->setTimezone (self ::$ defaultTimezone );
43+ }
44+ parent ::__construct ($ date );
3545 }
3646
3747 /**
@@ -61,16 +71,28 @@ public function getLocale(): ?string
6171 * @param string $localeCode
6272 * @return $this
6373 */
64- public function setLanguage (string $ localeCode ): self
74+ public function setLocale (string $ localeCode ): self
6575 {
6676 $ this ->locale = $ localeCode ;
6777 return $ this ;
6878 }
6979
70- // Alias to setLanguage
71- public function setLocale (string $ localeCode ): self
80+ // Alias to setLocale
81+ public function setLanguage (string $ localeCode ): self
7282 {
73- return $ this ->setLanguage ($ localeCode );
83+ return $ this ->setLocale ($ localeCode );
84+ }
85+
86+ /**
87+ * Set default timezone
88+ *
89+ * @param string|DateTimeZone $timezone
90+ * @return void
91+ * @throws \DateInvalidTimeZoneException
92+ */
93+ static public function setDefaultTimezone (string |DateTimeZone $ timezone ): void
94+ {
95+ self ::$ defaultTimezone = $ timezone instanceof DateTimeZone ? $ timezone : new DateTimeZone ($ timezone );
7496 }
7597
7698 /**
@@ -79,15 +101,15 @@ public function setLocale(string $localeCode): self
79101 * @param string $localeCode
80102 * @return void
81103 */
82- static public function setDefaultLanguage (string $ localeCode ): void
104+ static public function setDefaultLocale (string $ localeCode ): void
83105 {
84106 self ::$ defaultLocale = $ localeCode ;
85107 }
86108
87- // Alias to setDefaultLanguage
88- static public function setDefaultLocale (string $ localeCode ): void
109+ // Alias to setDefaultLocale
110+ static public function setDefaultLanguage (string $ localeCode ): void
89111 {
90- self ::setDefaultLanguage ($ localeCode );
112+ self ::setDefaultLocale ($ localeCode );
91113 }
92114
93115 /**
@@ -137,6 +159,220 @@ public function date(): string
137159 return $ this ->raw ->format ('Y-m-d ' );
138160 }
139161
162+ /**
163+ * Get hour and minutes
164+ *
165+ * @return string
166+ */
167+ public function time (): string
168+ {
169+ return $ this ->raw ->format ('H:i ' );
170+ }
171+
172+ /**
173+ * Get seconds (with leading zeros)
174+ *
175+ * @return string
176+ */
177+ public function seconds (): string
178+ {
179+ return $ this ->raw ->format ('s ' );
180+ }
181+
182+ /**
183+ * Check if year is leap year
184+ *
185+ * @return bool
186+ */
187+ public function isLeapYear (): bool
188+ {
189+ return (bool )$ this ->raw ->format ('L ' );
190+ }
191+
192+ /**
193+ * Get ISO 8601 week number of year
194+ *
195+ * @return int
196+ */
197+ public function weekNumber (): int
198+ {
199+ return (int )$ this ->raw ->format ('W ' );
200+ }
201+
202+ /**
203+ * Get ISO 8601 formatted date (e.g., 2025-03-20T14:30:00+01:00)
204+ *
205+ * @return string
206+ */
207+ public function iso (): string
208+ {
209+ return $ this ->raw ->format (DateTimeInterface::ATOM );
210+ }
211+
212+ /**
213+ * Get RFC 2822 formatted date (e.g., Thu, 20 Mar 2025 14:30:00 +0100)
214+ *
215+ * @return string
216+ */
217+ public function rfc (): string
218+ {
219+ return $ this ->raw ->format (DateTime::RFC2822 );
220+ }
221+
222+ /**
223+ * Get AM/PM format of time (e.g., 02:30 PM)
224+ *
225+ * @return string
226+ */
227+ public function time12Hour (): string
228+ {
229+ return $ this ->raw ->format ('h:i A ' );
230+ }
231+
232+ /**
233+ * Get difference in days from today (negative if in past, positive if future)
234+ *
235+ * @return int
236+ * @throws \DateMalformedStringException
237+ */
238+ public function diffInDays (): int
239+ {
240+ $ today = new DateTimeImmutable ('today ' , $ this ->raw ->getTimezone ());
241+ return (int )$ today ->diff ($ this ->raw )->format ('%r%a ' );
242+ }
243+
244+ /**
245+ * Check if the date is today
246+ *
247+ * @return bool
248+ */
249+ public function isToday (): bool
250+ {
251+ return $ this ->raw ->format ('Y-m-d ' ) === (new DateTimeImmutable ('today ' , $ this ->raw ->getTimezone ()))->format ('Y-m-d ' );
252+ }
253+
254+ /**
255+ * Set the timezone
256+ *
257+ * @param DateTimeZone|string $timezone
258+ * @return $this
259+ * @throws Exception
260+ */
261+ public function setTimezone (DateTimeZone |string $ timezone ): self
262+ {
263+ if (!$ timezone instanceof DateTimeZone) {
264+ $ timezone = new DateTimeZone ($ timezone );
265+ }
266+
267+ $ this ->raw = $ this ->raw ->setTimezone ($ timezone );
268+
269+ return $ this ;
270+ }
271+
272+
273+ /**
274+ * Get timezone identifier (e.g., Europe/Stockholm)
275+ *
276+ * @return string
277+ */
278+ public function timezone (): string
279+ {
280+ return $ this ->raw ->getTimezone ()->getName ();
281+ }
282+
283+ /**
284+ * Get hour and minutes
285+ *
286+ * @return string
287+ */
288+ public function timestamp (): string
289+ {
290+ return $ this ->raw ->getTimestamp ();
291+ }
292+
293+ /**
294+ * Get year
295+ *
296+ * @param bool $shorthand
297+ * @return string
298+ */
299+ public function year (bool $ shorthand = false ): string
300+ {
301+ return $ this ->raw ->format ($ shorthand ? 'y ' : 'Y ' );
302+ }
303+
304+ /**
305+ * Get month
306+ *
307+ * @return string
308+ */
309+ public function month (): string
310+ {
311+ return $ this ->raw ->format ("m " );
312+ }
313+
314+ /**
315+ * Get full name of month (e.g., January)
316+ *
317+ * @return string
318+ */
319+ public function monthName (): string
320+ {
321+ return $ this ->raw ->format ('F ' );
322+ }
323+
324+ /**
325+ * Get shorthand name of month (e.g., Jan)
326+ *
327+ * @return string
328+ */
329+ public function shortMonthName (): string
330+ {
331+ return $ this ->raw ->format ('M ' );
332+ }
333+
334+
335+ /**
336+ * Get month
337+ *
338+ * @return string
339+ */
340+ public function day (): string
341+ {
342+ return $ this ->raw ->format ("d " );
343+ }
344+
345+ /**
346+ * Get day of the week (numeric, 1 for Monday through 7 for Sunday)
347+ *
348+ * @return int
349+ */
350+ public function dayOfWeek (): int
351+ {
352+ return (int )$ this ->raw ->format ('N ' );
353+ }
354+
355+ /**
356+ * Get full name of the weekday (e.g., Monday)
357+ *
358+ * @return string
359+ */
360+ public function weekday (): string
361+ {
362+ return $ this ->raw ->format ('l ' );
363+ }
364+
365+ /**
366+ * Get short name of weekday (e.g., Mon)
367+ *
368+ * @return string
369+ */
370+ public function shortWeekday (): string
371+ {
372+ return $ this ->raw ->format ('D ' );
373+ }
374+
375+
140376 /**
141377 * Get Value
142378 * @return string
@@ -149,11 +385,11 @@ public function __toString(): string
149385 /**
150386 * Return translation find array
151387 *
152- * @param \ DateTime $date
388+ * @param DateTime $date
153389 * @param string $locale
154390 * @return array
155391 */
156- protected function getTranslationData (\ DateTime $ date , string $ locale ): array
392+ protected function getTranslationData (DateTime $ date , string $ locale ): array
157393 {
158394
159395 if ($ locale !== "en " ) {
0 commit comments