3 final class PhutilCalendarAbsoluteDateTime
4 extends PhutilCalendarDateTime
{
14 public static function newFromISO8601($value, $timezone = 'UTC') {
17 '(?P<y>\d{4})(?P<m>\d{2})(?P<d>\d{2})'.
19 'T(?P<h>\d{2})(?P<i>\d{2})(?P<s>\d{2})(?<z>Z)?'.
24 $ok = preg_match($pattern, $value, $matches);
28 'Expected ISO8601 datetime in the format "19990105T112233Z", '.
33 if (isset($matches['z'])) {
34 if ($timezone != 'UTC') {
37 'ISO8601 date ends in "Z" indicating UTC, but a timezone other '.
38 'than UTC ("%s") was specified.',
43 $datetime = id(new self())
44 ->setYear((int)$matches['y'])
45 ->setMonth((int)$matches['m'])
46 ->setDay((int)$matches['d'])
47 ->setTimezone($timezone);
49 if (isset($matches['h'])) {
51 ->setHour((int)$matches['h'])
52 ->setMinute((int)$matches['i'])
53 ->setSecond((int)$matches['s']);
62 public static function newFromEpoch($epoch, $timezone = 'UTC') {
63 $date = new DateTime('@'.$epoch);
65 $zone = new DateTimeZone($timezone);
66 $date->setTimezone($zone);
69 ->setYear((int)$date->format('Y'))
70 ->setMonth((int)$date->format('m'))
71 ->setDay((int)$date->format('d'))
72 ->setHour((int)$date->format('H'))
73 ->setMinute((int)$date->format('i'))
74 ->setSecond((int)$date->format('s'))
75 ->setTimezone($timezone);
78 public static function newFromDictionary(array $dict) {
95 foreach ($dict as $key => $value) {
96 if (!isset($keys[$key])) {
99 'Unexpected key "%s" in datetime dictionary, expected keys: %s.',
101 implode(', ', array_keys($keys))));
105 if (idx($dict, 'kind') !== 'absolute') {
108 'Expected key "%s" with value "%s" in datetime dictionary.',
113 if (!isset($dict['year'])) {
116 'Expected key "%s" in datetime dictionary.',
120 $datetime = id(new self())
121 ->setYear(idx($dict, 'year'))
122 ->setMonth(idx($dict, 'month', 1))
123 ->setDay(idx($dict, 'day', 1))
124 ->setHour(idx($dict, 'hour', 0))
125 ->setMinute(idx($dict, 'minute', 0))
126 ->setSecond(idx($dict, 'second', 0))
127 ->setTimezone(idx($dict, 'timezone'))
128 ->setIsAllDay((bool)idx($dict, 'isAllDay', false));
133 public function newRelativeDateTime($duration) {
134 if (is_string($duration)) {
135 $duration = PhutilCalendarDuration
::newFromISO8601($duration);
138 if (!($duration instanceof PhutilCalendarDuration
)) {
141 'Expected "PhutilCalendarDuration" object or ISO8601 duration '.
145 return id(new PhutilCalendarRelativeDateTime())
147 ->setDuration($duration);
150 public function toDictionary() {
152 'kind' => 'absolute',
153 'year' => (int)$this->getYear(),
154 'month' => (int)$this->getMonth(),
155 'day' => (int)$this->getDay(),
156 'hour' => (int)$this->getHour(),
157 'minute' => (int)$this->getMinute(),
158 'second' => (int)$this->getSecond(),
159 'timezone' => $this->getTimezone(),
160 'isAllDay' => (bool)$this->getIsAllDay(),
164 public function setYear($year) {
169 public function getYear() {
173 public function setMonth($month) {
174 $this->month
= $month;
178 public function getMonth() {
182 public function setDay($day) {
187 public function getDay() {
191 public function setHour($hour) {
196 public function getHour() {
200 public function setMinute($minute) {
201 $this->minute
= $minute;
205 public function getMinute() {
206 return $this->minute
;
209 public function setSecond($second) {
210 $this->second
= $second;
214 public function getSecond() {
215 return $this->second
;
218 public function setTimezone($timezone) {
219 $this->timezone
= $timezone;
223 public function getTimezone() {
224 return $this->timezone
;
227 private function getEffectiveTimezone() {
228 $date_timezone = $this->getTimezone();
229 $viewer_timezone = $this->getViewerTimezone();
231 // Because all-day events are always "floating", the effective timezone
232 // is the viewer timezone if it is available. Otherwise, we'll return a
233 // DateTime object with the correct values, but it will be incorrectly
234 // adjusted forward or backward to the viewer's zone later.
237 if ($this->getIsAllDay()) {
238 $zones[] = $viewer_timezone;
239 $zones[] = $date_timezone;
241 $zones[] = $date_timezone;
242 $zones[] = $viewer_timezone;
244 $zones = array_filter($zones);
249 'Datetime has no timezone or viewer timezone.'));
255 public function newPHPDateTimeZone() {
256 $zone = $this->getEffectiveTimezone();
257 return new DateTimeZone($zone);
260 public function newPHPDateTime() {
261 $zone = $this->newPHPDateTimeZone();
263 $y = $this->getYear();
264 $m = $this->getMonth();
265 $d = $this->getDay();
267 if ($this->getIsAllDay()) {
272 $h = $this->getHour();
273 $i = $this->getMinute();
274 $s = $this->getSecond();
277 $format = sprintf('%04d-%02d-%02d %02d:%02d:%02d', $y, $m, $d, $h, $i, $s);
279 return new DateTime($format, $zone);
283 public function newAbsoluteDateTime() {