@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class PhutilCalendarDuration extends Phobject {
4
5 private $isNegative = false;
6 private $weeks = 0;
7 private $days = 0;
8 private $hours = 0;
9 private $minutes = 0;
10 private $seconds = 0;
11
12 public static function newFromDictionary(array $dict) {
13 static $keys;
14 if ($keys === null) {
15 $keys = array_fuse(
16 array(
17 'isNegative',
18 'weeks',
19 'days',
20 'hours',
21 'minutes',
22 'seconds',
23 ));
24 }
25
26 foreach ($dict as $key => $value) {
27 if (!isset($keys[$key])) {
28 throw new Exception(
29 pht(
30 'Unexpected key "%s" in duration dictionary, expected keys: %s.',
31 $key,
32 implode(', ', array_keys($keys))));
33 }
34 }
35
36 $duration = id(new self())
37 ->setIsNegative(idx($dict, 'isNegative', false))
38 ->setWeeks(idx($dict, 'weeks', 0))
39 ->setDays(idx($dict, 'days', 0))
40 ->setHours(idx($dict, 'hours', 0))
41 ->setMinutes(idx($dict, 'minutes', 0))
42 ->setSeconds(idx($dict, 'seconds', 0));
43
44 return $duration;
45 }
46
47 public function toDictionary() {
48 return array(
49 'isNegative' => $this->getIsNegative(),
50 'weeks' => $this->getWeeks(),
51 'days' => $this->getDays(),
52 'hours' => $this->getHours(),
53 'minutes' => $this->getMinutes(),
54 'seconds' => $this->getSeconds(),
55 );
56 }
57
58 public static function newFromISO8601($value) {
59 $pattern =
60 '/^'.
61 '(?P<sign>[+-])?'.
62 'P'.
63 '(?:'.
64 '(?P<W>\d+)W'.
65 '|'.
66 '(?:(?:(?P<D>\d+)D)?'.
67 '(?:T(?:(?P<H>\d+)H)?(?:(?P<M>\d+)M)?(?:(?P<S>\d+)S)?)?'.
68 ')'.
69 ')'.
70 '\z/';
71
72 $matches = null;
73 $ok = preg_match($pattern, $value, $matches);
74 if (!$ok) {
75 throw new Exception(
76 pht(
77 'Expected ISO8601 duration in the format "P12DT3H4M5S", found '.
78 '"%s".',
79 $value));
80 }
81
82 $is_negative = (idx($matches, 'sign') == '-');
83
84 return id(new self())
85 ->setIsNegative($is_negative)
86 ->setWeeks((int)idx($matches, 'W', 0))
87 ->setDays((int)idx($matches, 'D', 0))
88 ->setHours((int)idx($matches, 'H', 0))
89 ->setMinutes((int)idx($matches, 'M', 0))
90 ->setSeconds((int)idx($matches, 'S', 0));
91 }
92
93 public function toISO8601() {
94 $parts = array();
95 $parts[] = 'P';
96
97 $weeks = $this->getWeeks();
98 if ($weeks) {
99 $parts[] = $weeks.'W';
100 } else {
101 $days = $this->getDays();
102 if ($days) {
103 $parts[] = $days.'D';
104 }
105
106 $parts[] = 'T';
107
108 $hours = $this->getHours();
109 if ($hours) {
110 $parts[] = $hours.'H';
111 }
112
113 $minutes = $this->getMinutes();
114 if ($minutes) {
115 $parts[] = $minutes.'M';
116 }
117
118 $seconds = $this->getSeconds();
119 if ($seconds) {
120 $parts[] = $seconds.'S';
121 }
122 }
123
124 return implode('', $parts);
125 }
126
127 public function setIsNegative($is_negative) {
128 $this->isNegative = $is_negative;
129 return $this;
130 }
131
132 public function getIsNegative() {
133 return $this->isNegative;
134 }
135
136 public function setWeeks($weeks) {
137 $this->weeks = $weeks;
138 return $this;
139 }
140
141 public function getWeeks() {
142 return $this->weeks;
143 }
144
145 public function setDays($days) {
146 $this->days = $days;
147 return $this;
148 }
149
150 public function getDays() {
151 return $this->days;
152 }
153
154 public function setHours($hours) {
155 $this->hours = $hours;
156 return $this;
157 }
158
159 public function getHours() {
160 return $this->hours;
161 }
162
163 public function setMinutes($minutes) {
164 $this->minutes = $minutes;
165 return $this;
166 }
167
168 public function getMinutes() {
169 return $this->minutes;
170 }
171
172 public function setSeconds($seconds) {
173 $this->seconds = $seconds;
174 return $this;
175 }
176
177 public function getSeconds() {
178 return $this->seconds;
179 }
180
181}