xref: /plugin/davcal/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php (revision a1a3b6794e0e143a4a8b51d3185ce2d339be61ab)
1*a1a3b679SAndreas Boehler<?php
2*a1a3b679SAndreas Boehler
3*a1a3b679SAndreas Boehlernamespace Sabre\VObject\Property\VCard;
4*a1a3b679SAndreas Boehler
5*a1a3b679SAndreas Boehleruse
6*a1a3b679SAndreas Boehler    Sabre\VObject\DateTimeParser,
7*a1a3b679SAndreas Boehler    Sabre\VObject\Property\Text,
8*a1a3b679SAndreas Boehler    Sabre\VObject\Property,
9*a1a3b679SAndreas Boehler    DateTime;
10*a1a3b679SAndreas Boehler
11*a1a3b679SAndreas Boehler/**
12*a1a3b679SAndreas Boehler * DateAndOrTime property
13*a1a3b679SAndreas Boehler *
14*a1a3b679SAndreas Boehler * This object encodes DATE-AND-OR-TIME values.
15*a1a3b679SAndreas Boehler *
16*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).
17*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/)
18*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License
19*a1a3b679SAndreas Boehler */
20*a1a3b679SAndreas Boehlerclass DateAndOrTime extends Property {
21*a1a3b679SAndreas Boehler
22*a1a3b679SAndreas Boehler    /**
23*a1a3b679SAndreas Boehler     * Field separator
24*a1a3b679SAndreas Boehler     *
25*a1a3b679SAndreas Boehler     * @var null|string
26*a1a3b679SAndreas Boehler     */
27*a1a3b679SAndreas Boehler    public $delimiter = null;
28*a1a3b679SAndreas Boehler
29*a1a3b679SAndreas Boehler    /**
30*a1a3b679SAndreas Boehler     * Returns the type of value.
31*a1a3b679SAndreas Boehler     *
32*a1a3b679SAndreas Boehler     * This corresponds to the VALUE= parameter. Every property also has a
33*a1a3b679SAndreas Boehler     * 'default' valueType.
34*a1a3b679SAndreas Boehler     *
35*a1a3b679SAndreas Boehler     * @return string
36*a1a3b679SAndreas Boehler     */
37*a1a3b679SAndreas Boehler    public function getValueType() {
38*a1a3b679SAndreas Boehler
39*a1a3b679SAndreas Boehler        return "DATE-AND-OR-TIME";
40*a1a3b679SAndreas Boehler
41*a1a3b679SAndreas Boehler    }
42*a1a3b679SAndreas Boehler
43*a1a3b679SAndreas Boehler    /**
44*a1a3b679SAndreas Boehler     * Sets a multi-valued property.
45*a1a3b679SAndreas Boehler     *
46*a1a3b679SAndreas Boehler     * You may also specify DateTime objects here.
47*a1a3b679SAndreas Boehler     *
48*a1a3b679SAndreas Boehler     * @param array $parts
49*a1a3b679SAndreas Boehler     * @return void
50*a1a3b679SAndreas Boehler     */
51*a1a3b679SAndreas Boehler    public function setParts(array $parts) {
52*a1a3b679SAndreas Boehler
53*a1a3b679SAndreas Boehler        if (count($parts)>1) {
54*a1a3b679SAndreas Boehler            throw new \InvalidArgumentException('Only one value allowed');
55*a1a3b679SAndreas Boehler        }
56*a1a3b679SAndreas Boehler        if (isset($parts[0]) && $parts[0] instanceof \DateTime) {
57*a1a3b679SAndreas Boehler            $this->setDateTime($parts[0]);
58*a1a3b679SAndreas Boehler        } else {
59*a1a3b679SAndreas Boehler            parent::setParts($parts);
60*a1a3b679SAndreas Boehler        }
61*a1a3b679SAndreas Boehler
62*a1a3b679SAndreas Boehler    }
63*a1a3b679SAndreas Boehler
64*a1a3b679SAndreas Boehler    /**
65*a1a3b679SAndreas Boehler     * Updates the current value.
66*a1a3b679SAndreas Boehler     *
67*a1a3b679SAndreas Boehler     * This may be either a single, or multiple strings in an array.
68*a1a3b679SAndreas Boehler     *
69*a1a3b679SAndreas Boehler     * Instead of strings, you may also use DateTime here.
70*a1a3b679SAndreas Boehler     *
71*a1a3b679SAndreas Boehler     * @param string|array|\DateTime $value
72*a1a3b679SAndreas Boehler     * @return void
73*a1a3b679SAndreas Boehler     */
74*a1a3b679SAndreas Boehler    public function setValue($value) {
75*a1a3b679SAndreas Boehler
76*a1a3b679SAndreas Boehler        if ($value instanceof \DateTime) {
77*a1a3b679SAndreas Boehler            $this->setDateTime($value);
78*a1a3b679SAndreas Boehler        } else {
79*a1a3b679SAndreas Boehler            parent::setValue($value);
80*a1a3b679SAndreas Boehler        }
81*a1a3b679SAndreas Boehler
82*a1a3b679SAndreas Boehler    }
83*a1a3b679SAndreas Boehler
84*a1a3b679SAndreas Boehler    /**
85*a1a3b679SAndreas Boehler     * Sets the property as a DateTime object.
86*a1a3b679SAndreas Boehler     *
87*a1a3b679SAndreas Boehler     * @param \DateTime $dt
88*a1a3b679SAndreas Boehler     * @return void
89*a1a3b679SAndreas Boehler     */
90*a1a3b679SAndreas Boehler    public function setDateTime(\DateTime $dt) {
91*a1a3b679SAndreas Boehler
92*a1a3b679SAndreas Boehler        $values = array();
93*a1a3b679SAndreas Boehler
94*a1a3b679SAndreas Boehler        $tz = null;
95*a1a3b679SAndreas Boehler        $isUtc = false;
96*a1a3b679SAndreas Boehler
97*a1a3b679SAndreas Boehler        $tz = $dt->getTimeZone();
98*a1a3b679SAndreas Boehler        $isUtc = in_array($tz->getName() , array('UTC', 'GMT', 'Z'));
99*a1a3b679SAndreas Boehler
100*a1a3b679SAndreas Boehler        if ($isUtc) {
101*a1a3b679SAndreas Boehler            $value = $dt->format('Ymd\\THis\\Z');
102*a1a3b679SAndreas Boehler        } else {
103*a1a3b679SAndreas Boehler            // Calculating the offset.
104*a1a3b679SAndreas Boehler            $value = $dt->format('Ymd\\THisO');
105*a1a3b679SAndreas Boehler        }
106*a1a3b679SAndreas Boehler
107*a1a3b679SAndreas Boehler        $this->value = $value;
108*a1a3b679SAndreas Boehler
109*a1a3b679SAndreas Boehler    }
110*a1a3b679SAndreas Boehler
111*a1a3b679SAndreas Boehler    /**
112*a1a3b679SAndreas Boehler     * Returns a date-time value.
113*a1a3b679SAndreas Boehler     *
114*a1a3b679SAndreas Boehler     * Note that if this property contained more than 1 date-time, only the
115*a1a3b679SAndreas Boehler     * first will be returned. To get an array with multiple values, call
116*a1a3b679SAndreas Boehler     * getDateTimes.
117*a1a3b679SAndreas Boehler     *
118*a1a3b679SAndreas Boehler     * If no time was specified, we will always use midnight (in the default
119*a1a3b679SAndreas Boehler     * timezone) as the time.
120*a1a3b679SAndreas Boehler     *
121*a1a3b679SAndreas Boehler     * If parts of the date were omitted, such as the year, we will grab the
122*a1a3b679SAndreas Boehler     * current values for those. So at the time of writing, if the year was
123*a1a3b679SAndreas Boehler     * omitted, we would have filled in 2014.
124*a1a3b679SAndreas Boehler     *
125*a1a3b679SAndreas Boehler     * @return \DateTime
126*a1a3b679SAndreas Boehler     */
127*a1a3b679SAndreas Boehler    public function getDateTime() {
128*a1a3b679SAndreas Boehler
129*a1a3b679SAndreas Boehler        $dts = array();
130*a1a3b679SAndreas Boehler        $now = new DateTime();
131*a1a3b679SAndreas Boehler
132*a1a3b679SAndreas Boehler        $tzFormat = $now->getTimezone()->getOffset($now)===0?'\\Z':'O';
133*a1a3b679SAndreas Boehler        $nowParts = DateTimeParser::parseVCardDateTime($now->format('Ymd\\This' . $tzFormat));
134*a1a3b679SAndreas Boehler
135*a1a3b679SAndreas Boehler        $value = $this->getValue();
136*a1a3b679SAndreas Boehler
137*a1a3b679SAndreas Boehler        $dateParts = DateTimeParser::parseVCardDateTime($this->getValue());
138*a1a3b679SAndreas Boehler
139*a1a3b679SAndreas Boehler        // This sets all the missing parts to the current date/time.
140*a1a3b679SAndreas Boehler        // So if the year was missing for a birthday, we're making it 'this
141*a1a3b679SAndreas Boehler        // year'.
142*a1a3b679SAndreas Boehler        foreach($dateParts as $k=>$v) {
143*a1a3b679SAndreas Boehler            if (is_null($v)) {
144*a1a3b679SAndreas Boehler                $dateParts[$k] = $nowParts[$k];
145*a1a3b679SAndreas Boehler            }
146*a1a3b679SAndreas Boehler        }
147*a1a3b679SAndreas Boehler        return new DateTime("$dateParts[year]-$dateParts[month]-$dateParts[date] $dateParts[hour]:$dateParts[minute]:$dateParts[second] $dateParts[timezone]");
148*a1a3b679SAndreas Boehler
149*a1a3b679SAndreas Boehler    }
150*a1a3b679SAndreas Boehler
151*a1a3b679SAndreas Boehler    /**
152*a1a3b679SAndreas Boehler     * Returns the value, in the format it should be encoded for json.
153*a1a3b679SAndreas Boehler     *
154*a1a3b679SAndreas Boehler     * This method must always return an array.
155*a1a3b679SAndreas Boehler     *
156*a1a3b679SAndreas Boehler     * @return array
157*a1a3b679SAndreas Boehler     */
158*a1a3b679SAndreas Boehler    public function getJsonValue() {
159*a1a3b679SAndreas Boehler
160*a1a3b679SAndreas Boehler        $parts = DateTimeParser::parseVCardDateTime($this->getValue());
161*a1a3b679SAndreas Boehler
162*a1a3b679SAndreas Boehler        $dateStr = '';
163*a1a3b679SAndreas Boehler
164*a1a3b679SAndreas Boehler        // Year
165*a1a3b679SAndreas Boehler        if (!is_null($parts['year'])) {
166*a1a3b679SAndreas Boehler            $dateStr.=$parts['year'];
167*a1a3b679SAndreas Boehler
168*a1a3b679SAndreas Boehler            if (!is_null($parts['month'])) {
169*a1a3b679SAndreas Boehler                // If a year and a month is set, we need to insert a separator
170*a1a3b679SAndreas Boehler                // dash.
171*a1a3b679SAndreas Boehler                $dateStr.='-';
172*a1a3b679SAndreas Boehler            }
173*a1a3b679SAndreas Boehler
174*a1a3b679SAndreas Boehler        } else {
175*a1a3b679SAndreas Boehler
176*a1a3b679SAndreas Boehler            if (!is_null($parts['month']) || !is_null($parts['date'])) {
177*a1a3b679SAndreas Boehler                // Inserting two dashes
178*a1a3b679SAndreas Boehler                $dateStr.='--';
179*a1a3b679SAndreas Boehler            }
180*a1a3b679SAndreas Boehler
181*a1a3b679SAndreas Boehler        }
182*a1a3b679SAndreas Boehler
183*a1a3b679SAndreas Boehler        // Month
184*a1a3b679SAndreas Boehler
185*a1a3b679SAndreas Boehler        if (!is_null($parts['month'])) {
186*a1a3b679SAndreas Boehler            $dateStr.=$parts['month'];
187*a1a3b679SAndreas Boehler
188*a1a3b679SAndreas Boehler            if (isset($parts['date'])) {
189*a1a3b679SAndreas Boehler                // If month and date are set, we need the separator dash.
190*a1a3b679SAndreas Boehler                $dateStr.='-';
191*a1a3b679SAndreas Boehler            }
192*a1a3b679SAndreas Boehler        } else {
193*a1a3b679SAndreas Boehler            if (isset($parts['date'])) {
194*a1a3b679SAndreas Boehler                // If the month is empty, and a date is set, we need a 'empty
195*a1a3b679SAndreas Boehler                // dash'
196*a1a3b679SAndreas Boehler                $dateStr.='-';
197*a1a3b679SAndreas Boehler            }
198*a1a3b679SAndreas Boehler        }
199*a1a3b679SAndreas Boehler
200*a1a3b679SAndreas Boehler        // Date
201*a1a3b679SAndreas Boehler        if (!is_null($parts['date'])) {
202*a1a3b679SAndreas Boehler            $dateStr.=$parts['date'];
203*a1a3b679SAndreas Boehler        }
204*a1a3b679SAndreas Boehler
205*a1a3b679SAndreas Boehler
206*a1a3b679SAndreas Boehler        // Early exit if we don't have a time string.
207*a1a3b679SAndreas Boehler        if (is_null($parts['hour']) && is_null($parts['minute']) && is_null($parts['second'])) {
208*a1a3b679SAndreas Boehler            return array($dateStr);
209*a1a3b679SAndreas Boehler        }
210*a1a3b679SAndreas Boehler
211*a1a3b679SAndreas Boehler        $dateStr.='T';
212*a1a3b679SAndreas Boehler
213*a1a3b679SAndreas Boehler        // Hour
214*a1a3b679SAndreas Boehler        if (!is_null($parts['hour'])) {
215*a1a3b679SAndreas Boehler            $dateStr.=$parts['hour'];
216*a1a3b679SAndreas Boehler
217*a1a3b679SAndreas Boehler            if (!is_null($parts['minute'])) {
218*a1a3b679SAndreas Boehler                $dateStr.=':';
219*a1a3b679SAndreas Boehler            }
220*a1a3b679SAndreas Boehler        } else {
221*a1a3b679SAndreas Boehler            // We know either minute or second _must_ be set, so we insert a
222*a1a3b679SAndreas Boehler            // dash for an empty value.
223*a1a3b679SAndreas Boehler            $dateStr.='-';
224*a1a3b679SAndreas Boehler        }
225*a1a3b679SAndreas Boehler
226*a1a3b679SAndreas Boehler        // Minute
227*a1a3b679SAndreas Boehler        if (!is_null($parts['minute'])) {
228*a1a3b679SAndreas Boehler            $dateStr.=$parts['minute'];
229*a1a3b679SAndreas Boehler
230*a1a3b679SAndreas Boehler            if (!is_null($parts['second'])) {
231*a1a3b679SAndreas Boehler                $dateStr.=':';
232*a1a3b679SAndreas Boehler            }
233*a1a3b679SAndreas Boehler        } else {
234*a1a3b679SAndreas Boehler            if (isset($parts['second'])) {
235*a1a3b679SAndreas Boehler                // Dash for empty minute
236*a1a3b679SAndreas Boehler                $dateStr.='-';
237*a1a3b679SAndreas Boehler            }
238*a1a3b679SAndreas Boehler        }
239*a1a3b679SAndreas Boehler
240*a1a3b679SAndreas Boehler        // Second
241*a1a3b679SAndreas Boehler        if (!is_null($parts['second'])) {
242*a1a3b679SAndreas Boehler            $dateStr.=$parts['second'];
243*a1a3b679SAndreas Boehler        }
244*a1a3b679SAndreas Boehler
245*a1a3b679SAndreas Boehler        // Timezone
246*a1a3b679SAndreas Boehler        if (!is_null($parts['timezone'])) {
247*a1a3b679SAndreas Boehler            $dateStr.=$parts['timezone'];
248*a1a3b679SAndreas Boehler        }
249*a1a3b679SAndreas Boehler
250*a1a3b679SAndreas Boehler        return array($dateStr);
251*a1a3b679SAndreas Boehler
252*a1a3b679SAndreas Boehler    }
253*a1a3b679SAndreas Boehler
254*a1a3b679SAndreas Boehler    /**
255*a1a3b679SAndreas Boehler     * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
256*a1a3b679SAndreas Boehler     *
257*a1a3b679SAndreas Boehler     * This has been 'unfolded', so only 1 line will be passed. Unescaping is
258*a1a3b679SAndreas Boehler     * not yet done, but parameters are not included.
259*a1a3b679SAndreas Boehler     *
260*a1a3b679SAndreas Boehler     * @param string $val
261*a1a3b679SAndreas Boehler     * @return void
262*a1a3b679SAndreas Boehler     */
263*a1a3b679SAndreas Boehler    public function setRawMimeDirValue($val) {
264*a1a3b679SAndreas Boehler
265*a1a3b679SAndreas Boehler        $this->setValue($val);
266*a1a3b679SAndreas Boehler
267*a1a3b679SAndreas Boehler    }
268*a1a3b679SAndreas Boehler
269*a1a3b679SAndreas Boehler    /**
270*a1a3b679SAndreas Boehler     * Returns a raw mime-dir representation of the value.
271*a1a3b679SAndreas Boehler     *
272*a1a3b679SAndreas Boehler     * @return string
273*a1a3b679SAndreas Boehler     */
274*a1a3b679SAndreas Boehler    public function getRawMimeDirValue() {
275*a1a3b679SAndreas Boehler
276*a1a3b679SAndreas Boehler        return implode($this->delimiter, $this->getParts());
277*a1a3b679SAndreas Boehler
278*a1a3b679SAndreas Boehler    }
279*a1a3b679SAndreas Boehler
280*a1a3b679SAndreas Boehler    /**
281*a1a3b679SAndreas Boehler     * Validates the node for correctness.
282*a1a3b679SAndreas Boehler     *
283*a1a3b679SAndreas Boehler     * The following options are supported:
284*a1a3b679SAndreas Boehler     *   Node::REPAIR - May attempt to automatically repair the problem.
285*a1a3b679SAndreas Boehler     *
286*a1a3b679SAndreas Boehler     * This method returns an array with detected problems.
287*a1a3b679SAndreas Boehler     * Every element has the following properties:
288*a1a3b679SAndreas Boehler     *
289*a1a3b679SAndreas Boehler     *  * level - problem level.
290*a1a3b679SAndreas Boehler     *  * message - A human-readable string describing the issue.
291*a1a3b679SAndreas Boehler     *  * node - A reference to the problematic node.
292*a1a3b679SAndreas Boehler     *
293*a1a3b679SAndreas Boehler     * The level means:
294*a1a3b679SAndreas Boehler     *   1 - The issue was repaired (only happens if REPAIR was turned on)
295*a1a3b679SAndreas Boehler     *   2 - An inconsequential issue
296*a1a3b679SAndreas Boehler     *   3 - A severe issue.
297*a1a3b679SAndreas Boehler     *
298*a1a3b679SAndreas Boehler     * @param int $options
299*a1a3b679SAndreas Boehler     * @return array
300*a1a3b679SAndreas Boehler     */
301*a1a3b679SAndreas Boehler    public function validate($options = 0) {
302*a1a3b679SAndreas Boehler
303*a1a3b679SAndreas Boehler        $messages = parent::validate($options);
304*a1a3b679SAndreas Boehler        $value = $this->getValue();
305*a1a3b679SAndreas Boehler        try {
306*a1a3b679SAndreas Boehler            DateTimeParser::parseVCardDateTime($value);
307*a1a3b679SAndreas Boehler        } catch (\InvalidArgumentException $e) {
308*a1a3b679SAndreas Boehler            $messages[] = array(
309*a1a3b679SAndreas Boehler                'level' => 3,
310*a1a3b679SAndreas Boehler                'message' => 'The supplied value (' . $value . ') is not a correct DATE-AND-OR-TIME property',
311*a1a3b679SAndreas Boehler                'node' => $this,
312*a1a3b679SAndreas Boehler            );
313*a1a3b679SAndreas Boehler        }
314*a1a3b679SAndreas Boehler        return $messages;
315*a1a3b679SAndreas Boehler
316*a1a3b679SAndreas Boehler    }
317*a1a3b679SAndreas Boehler}
318