1: <?php declare(strict_types=1);
2:
3: namespace Salient\Utility;
4:
5: use DateInterval;
6: use DateTimeImmutable;
7: use DateTimeInterface;
8: use DateTimeZone;
9: use InvalidArgumentException;
10:
11: /**
12: * Work with date and time values, timezones and intervals
13: *
14: * @api
15: */
16: final class Date extends AbstractUtility
17: {
18: /**
19: * Get a DateTimeImmutable from a DateTimeInterface
20: *
21: * A shim for {@see DateTimeImmutable::createFromInterface()}.
22: */
23: public static function immutable(DateTimeInterface $datetime): DateTimeImmutable
24: {
25: return $datetime instanceof DateTimeImmutable
26: ? $datetime
27: : DateTimeImmutable::createFromMutable($datetime);
28: }
29:
30: /**
31: * Get a DateTimeZone from a string or DateTimeZone
32: *
33: * @param DateTimeZone|string|null $timezone If `null`, the timezone
34: * returned by {@see date_default_timezone_get()} is used.
35: */
36: public static function timezone($timezone = null): DateTimeZone
37: {
38: if ($timezone instanceof DateTimeZone) {
39: return $timezone;
40: }
41: if ($timezone === null) {
42: $timezone = date_default_timezone_get();
43: }
44: return new DateTimeZone($timezone);
45: }
46:
47: /**
48: * Get a DateInterval or ISO-8601 duration in seconds
49: *
50: * @param DateInterval|string $interval
51: */
52: public static function duration($interval): int
53: {
54: if (!$interval instanceof DateInterval) {
55: if (
56: \PHP_VERSION_ID < 80000
57: && Regex::match('/W.+D/', $interval)
58: ) {
59: throw new InvalidArgumentException(sprintf(
60: 'Invalid $interval: %s',
61: $interval,
62: ));
63: }
64: $interval = new DateInterval($interval);
65: }
66:
67: $then = new DateTimeImmutable();
68: $now = $then->add($interval);
69:
70: return $now->getTimestamp() - $then->getTimestamp();
71: }
72:
73: /**
74: * Set the timezone of a date and time if not already set
75: *
76: * @param DateTimeZone|string|null $timezone If `null`, the timezone
77: * returned by {@see date_default_timezone_get()} is used.
78: */
79: public static function maybeSetTimezone(DateTimeInterface $datetime, $timezone = null): DateTimeImmutable
80: {
81: $datetime = self::immutable($datetime);
82: $tz = $datetime->getTimezone()->getName();
83: if ($tz === 'UTC' && ($timezone !== null || date_default_timezone_get() !== 'UTC')) {
84: $timezone = self::timezone($timezone);
85: if ($tz !== $timezone->getName()) {
86: return $datetime->setTimezone($timezone);
87: }
88: }
89: return $datetime;
90: }
91: }
92: