commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / packages / Date.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
3
4 // {{{ Header
5
6 /**
7 * Generic date handling class for PEAR
8 *
9 * Generic date handling class for PEAR. Attempts to be time zone aware
10 * through the Date::TimeZone class. Supports several operations from
11 * Date::Calc on Date objects.
12 *
13 * PHP versions 4 and 5
14 *
15 * LICENSE:
16 *
17 * Copyright (c) 1997-2006 Baba Buehler, Pierre-Alain Joye
18 * All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted under the terms of the BSD License.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 * @category Date and Time
37 * @package Date
38 * @author Baba Buehler <baba@babaz.com>
39 * @author Pierre-Alain Joye <pajoye@php.net>
40 * @author Firman Wandayandi <firman@php.net>
41 * @copyright 1997-2006 Baba Buehler, Pierre-Alain Joye
42 * @license http://www.opensource.org/licenses/bsd-license.php
43 * BSD License
44 * @version CVS: $Id: Date.php,v 1.41 2006/11/22 00:28:03 firman Exp $
45 * @link http://pear.php.net/package/Date
46 */
47
48 // }}}
49
50 // {{{ Includes
51
52 /**
53 * Load Date_TimeZone.
54 */
55 require_once 'Date/TimeZone.php';
56
57 /**
58 * Load Date_Calc.
59 */
60 require_once 'Date/Calc.php';
61
62 /**
63 * Load Date_Span.
64 */
65 require_once 'Date/Span.php';
66
67 // }}}
68 // {{{ Constants
69
70 // {{{ Output formats Pass this to getDate().
71
72 /**
73 * "YYYY-MM-DD HH:MM:SS"
74 */
75 define('DATE_FORMAT_ISO', 1);
76
77 /**
78 * "YYYYMMSSTHHMMSS(Z|(+/-)HHMM)?"
79 */
80 define('DATE_FORMAT_ISO_BASIC', 2);
81
82 /**
83 * "YYYY-MM-SSTHH:MM:SS(Z|(+/-)HH:MM)?"
84 */
85 define('DATE_FORMAT_ISO_EXTENDED', 3);
86
87 /**
88 * "YYYY-MM-SSTHH:MM:SS(.S*)?(Z|(+/-)HH:MM)?"
89 */
90 define('DATE_FORMAT_ISO_EXTENDED_MICROTIME', 6);
91
92 /**
93 * "YYYYMMDDHHMMSS"
94 */
95 define('DATE_FORMAT_TIMESTAMP', 4);
96
97 /**
98 * long int, seconds since the unix epoch
99 */
100 define('DATE_FORMAT_UNIXTIME', 5);
101
102 // }}}
103
104 // }}}
105 // {{{ Class: Date
106
107 /**
108 * Generic date handling class for PEAR
109 *
110 * Generic date handling class for PEAR. Attempts to be time zone aware
111 * through the Date::TimeZone class. Supports several operations from
112 * Date::Calc on Date objects.
113 *
114 * @author Baba Buehler <baba@babaz.com>
115 * @author Pierre-Alain Joye <pajoye@php.net>
116 * @author Firman Wandayandi <firman@php.net>
117 * @copyright 1997-2006 Baba Buehler, Pierre-Alain Joye
118 * @license http://www.opensource.org/licenses/bsd-license.php
119 * BSD License
120 * @version Release: 1.4.7
121 * @link http://pear.php.net/package/Date
122 */
123 class Date
124 {
125 // {{{ Properties
126
127 /**
128 * the year
129 * @var int
130 */
131 var $year;
132
133 /**
134 * the month
135 * @var int
136 */
137 var $month;
138
139 /**
140 * the day
141 * @var int
142 */
143 var $day;
144
145 /**
146 * the hour
147 * @var int
148 */
149 var $hour;
150
151 /**
152 * the minute
153 * @var int
154 */
155 var $minute;
156
157 /**
158 * the second
159 * @var int
160 */
161 var $second;
162
163 /**
164 * the parts of a second
165 * @var float
166 */
167 var $partsecond;
168
169 /**
170 * timezone for this date
171 * @var object Date_TimeZone
172 */
173 var $tz;
174
175 /**
176 * define the default weekday abbreviation length
177 * used by ::format()
178 * @var int
179 */
180 var $getWeekdayAbbrnameLength = 3;
181
182 // }}}
183 // {{{ Constructor
184
185 /**
186 * Constructor
187 *
188 * Creates a new Date Object initialized to the current date/time in the
189 * system-default timezone by default. A date optionally
190 * passed in may be in the ISO 8601, TIMESTAMP or UNIXTIME format,
191 * or another Date object. If no date is passed, the current date/time
192 * is used.
193 *
194 * @access public
195 * @see setDate()
196 * @param mixed $date optional - date/time to initialize
197 * @return object Date the new Date object
198 */
199 function Date($date = null)
200 {
201 $this->tz = Date_TimeZone::getDefault();
202 if (is_null($date)) {
203 $this->setDate(date("Y-m-d H:i:s"));
204 } elseif (is_a($date, 'Date')) {
205 $this->copy($date);
206 } else {
207 $this->setDate($date);
208 }
209 }
210
211 // }}}
212 // {{{ setDate()
213
214 /**
215 * Set the fields of a Date object based on the input date and format
216 *
217 * Set the fields of a Date object based on the input date and format,
218 * which is specified by the DATE_FORMAT_* constants.
219 *
220 * @access public
221 * @param string $date input date
222 * @param int $format Optional format constant (DATE_FORMAT_*) of the input date.
223 * This parameter isn't really needed anymore, but you could
224 * use it to force DATE_FORMAT_UNIXTIME.
225 */
226 function setDate($date, $format = DATE_FORMAT_ISO)
227 {
228 if (
229 preg_match('/^(\d{4})-?(\d{2})-?(\d{2})([T\s]?(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?(Z|[\+\-]\d{2}:?\d{2})?)?$/i', $date, $regs)
230 && $format != DATE_FORMAT_UNIXTIME) {
231 // DATE_FORMAT_ISO, ISO_BASIC, ISO_EXTENDED, and TIMESTAMP
232 // These formats are extremely close to each other. This regex
233 // is very loose and accepts almost any butchered format you could
234 // throw at it. e.g. 2003-10-07 19:45:15 and 2003-10071945:15
235 // are the same thing in the eyes of this regex, even though the
236 // latter is not a valid ISO 8601 date.
237 $this->year = $regs[1];
238 $this->month = $regs[2];
239 $this->day = $regs[3];
240 $this->hour = isset($regs[5])?$regs[5]:0;
241 $this->minute = isset($regs[6])?$regs[6]:0;
242 $this->second = isset($regs[7])?$regs[7]:0;
243 $this->partsecond = isset($regs[8])?(float)$regs[8]:(float)0;
244
245 // if an offset is defined, convert time to UTC
246 // Date currently can't set a timezone only by offset,
247 // so it has to store it as UTC
248 if (isset($regs[9])) {
249 $this->toUTCbyOffset($regs[9]);
250 }
251 } elseif (is_numeric($date)) {
252 // UNIXTIME
253 $this->setDate(date("Y-m-d H:i:s", $date));
254 } else {
255 // unknown format
256 $this->year = 0;
257 $this->month = 1;
258 $this->day = 1;
259 $this->hour = 0;
260 $this->minute = 0;
261 $this->second = 0;
262 $this->partsecond = (float)0;
263 }
264 }
265
266 // }}}
267 // {{{ getDate()
268
269 /**
270 * Get a string (or other) representation of this date
271 *
272 * Get a string (or other) representation of this date in the
273 * format specified by the DATE_FORMAT_* constants.
274 *
275 * @access public
276 * @param int $format format constant (DATE_FORMAT_*) of the output date
277 * @return string the date in the requested format
278 */
279 function getDate($format = DATE_FORMAT_ISO)
280 {
281 switch ($format) {
282 case DATE_FORMAT_ISO:
283 return $this->format("%Y-%m-%d %T");
284 break;
285 case DATE_FORMAT_ISO_BASIC:
286 $format = "%Y%m%dT%H%M%S";
287 if ($this->tz->getID() == 'UTC') {
288 $format .= "Z";
289 }
290 return $this->format($format);
291 break;
292 case DATE_FORMAT_ISO_EXTENDED:
293 $format = "%Y-%m-%dT%H:%M:%S";
294 if ($this->tz->getID() == 'UTC') {
295 $format .= "Z";
296 }
297 return $this->format($format);
298 break;
299 case DATE_FORMAT_ISO_EXTENDED_MICROTIME:
300 $format = "%Y-%m-%dT%H:%M:%s";
301 if ($this->tz->getID() == 'UTC') {
302 $format .= "Z";
303 }
304 return $this->format($format);
305 break;
306 case DATE_FORMAT_TIMESTAMP:
307 return $this->format("%Y%m%d%H%M%S");
308 break;
309 case DATE_FORMAT_UNIXTIME:
310 return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
311 break;
312 }
313 }
314
315 // }}}
316 // {{{ copy()
317
318 /**
319 * Copy values from another Date object
320 *
321 * Makes this Date a copy of another Date object.
322 *
323 * @access public
324 * @param object Date $date Date to copy from
325 */
326 function copy($date)
327 {
328 $this->year = $date->year;
329 $this->month = $date->month;
330 $this->day = $date->day;
331 $this->hour = $date->hour;
332 $this->minute = $date->minute;
333 $this->second = $date->second;
334 $this->tz = $date->tz;
335 }
336
337 // }}}
338 // {{{ format()
339
340 /**
341 * Date pretty printing, similar to strftime()
342 *
343 * Formats the date in the given format, much like
344 * strftime(). Most strftime() options are supported.<br><br>
345 *
346 * formatting options:<br><br>
347 *
348 * <code>%a </code> abbreviated weekday name (Sun, Mon, Tue) <br>
349 * <code>%A </code> full weekday name (Sunday, Monday, Tuesday) <br>
350 * <code>%b </code> abbreviated month name (Jan, Feb, Mar) <br>
351 * <code>%B </code> full month name (January, February, March) <br>
352 * <code>%C </code> century number (the year divided by 100 and truncated to an integer, range 00 to 99) <br>
353 * <code>%d </code> day of month (range 00 to 31) <br>
354 * <code>%D </code> same as "%m/%d/%y" <br>
355 * <code>%e </code> day of month, single digit (range 0 to 31) <br>
356 * <code>%E </code> number of days since unspecified epoch (integer, Date_Calc::dateToDays()) <br>
357 * <code>%H </code> hour as decimal number (00 to 23) <br>
358 * <code>%I </code> hour as decimal number on 12-hour clock (01 to 12) <br>
359 * <code>%j </code> day of year (range 001 to 366) <br>
360 * <code>%m </code> month as decimal number (range 01 to 12) <br>
361 * <code>%M </code> minute as a decimal number (00 to 59) <br>
362 * <code>%n </code> newline character (\n) <br>
363 * <code>%O </code> dst-corrected timezone offset expressed as "+/-HH:MM" <br>
364 * <code>%o </code> raw timezone offset expressed as "+/-HH:MM" <br>
365 * <code>%p </code> either 'am' or 'pm' depending on the time <br>
366 * <code>%P </code> either 'AM' or 'PM' depending on the time <br>
367 * <code>%r </code> time in am/pm notation, same as "%I:%M:%S %p" <br>
368 * <code>%R </code> time in 24-hour notation, same as "%H:%M" <br>
369 * <code>%s </code> seconds including the decimal representation smaller than one second <br>
370 * <code>%S </code> seconds as a decimal number (00 to 59) <br>
371 * <code>%t </code> tab character (\t) <br>
372 * <code>%T </code> current time, same as "%H:%M:%S" <br>
373 * <code>%w </code> weekday as decimal (0 = Sunday) <br>
374 * <code>%U </code> week number of current year, first sunday as first week <br>
375 * <code>%y </code> year as decimal (range 00 to 99) <br>
376 * <code>%Y </code> year as decimal including century (range 0000 to 9999) <br>
377 * <code>%% </code> literal '%' <br>
378 * <br>
379 *
380 * @access public
381 * @param string format the format string for returned date/time
382 * @return string date/time in given format
383 */
384 function format($format)
385 {
386 $output = "";
387
388 for($strpos = 0; $strpos < strlen($format); $strpos++) {
389 $char = substr($format,$strpos,1);
390 if ($char == "%") {
391 $nextchar = substr($format,$strpos + 1,1);
392 switch ($nextchar) {
393 case "a":
394 $output .= Date_Calc::getWeekdayAbbrname($this->day,$this->month,$this->year, $this->getWeekdayAbbrnameLength);
395 break;
396 case "A":
397 $output .= Date_Calc::getWeekdayFullname($this->day,$this->month,$this->year);
398 break;
399 case "b":
400 $output .= Date_Calc::getMonthAbbrname($this->month);
401 break;
402 case "B":
403 $output .= Date_Calc::getMonthFullname($this->month);
404 break;
405 case "C":
406 $output .= sprintf("%02d",intval($this->year/100));
407 break;
408 case "d":
409 $output .= sprintf("%02d",$this->day);
410 break;
411 case "D":
412 $output .= sprintf("%02d/%02d/%02d",$this->month,$this->day,$this->year);
413 break;
414 case "e":
415 $output .= $this->day * 1; // get rid of leading zero
416 break;
417 case "E":
418 $output .= Date_Calc::dateToDays($this->day,$this->month,$this->year);
419 break;
420 case "H":
421 $output .= sprintf("%02d", $this->hour);
422 break;
423 case 'h':
424 $output .= sprintf("%d", $this->hour);
425 break;
426 case "I":
427 $hour = ($this->hour + 1) > 12 ? $this->hour - 12 : $this->hour;
428 $output .= sprintf("%02d", $hour==0 ? 12 : $hour);
429 break;
430 case "i":
431 $hour = ($this->hour + 1) > 12 ? $this->hour - 12 : $this->hour;
432 $output .= sprintf("%d", $hour==0 ? 12 : $hour);
433 break;
434 case "j":
435 $output .= Date_Calc::julianDate($this->day,$this->month,$this->year);
436 break;
437 case "m":
438 $output .= sprintf("%02d",$this->month);
439 break;
440 case "M":
441 $output .= sprintf("%02d",$this->minute);
442 break;
443 case "n":
444 $output .= "\n";
445 break;
446 case "O":
447 $offms = $this->tz->getOffset($this);
448 $direction = $offms >= 0 ? "+" : "-";
449 $offmins = abs($offms) / 1000 / 60;
450 $hours = $offmins / 60;
451 $minutes = $offmins % 60;
452 $output .= sprintf("%s%02d:%02d", $direction, $hours, $minutes);
453 break;
454 case "o":
455 $offms = $this->tz->getRawOffset($this);
456 $direction = $offms >= 0 ? "+" : "-";
457 $offmins = abs($offms) / 1000 / 60;
458 $hours = $offmins / 60;
459 $minutes = $offmins % 60;
460 $output .= sprintf("%s%02d:%02d", $direction, $hours, $minutes);
461 break;
462 case "p":
463 $output .= $this->hour >= 12 ? "pm" : "am";
464 break;
465 case "P":
466 $output .= $this->hour >= 12 ? "PM" : "AM";
467 break;
468 case "r":
469 $hour = ($this->hour + 1) > 12 ? $this->hour - 12 : $this->hour;
470 $output .= sprintf("%02d:%02d:%02d %s", $hour==0 ? 12 : $hour, $this->minute, $this->second, $this->hour >= 12 ? "PM" : "AM");
471 break;
472 case "R":
473 $output .= sprintf("%02d:%02d", $this->hour, $this->minute);
474 break;
475 case "s":
476 $output .= str_replace(',', '.', sprintf("%09f", (float)((float)$this->second + $this->partsecond)));
477 break;
478 case "S":
479 $output .= sprintf("%02d", $this->second);
480 break;
481 case "t":
482 $output .= "\t";
483 break;
484 case "T":
485 $output .= sprintf("%02d:%02d:%02d", $this->hour, $this->minute, $this->second);
486 break;
487 case "w":
488 $output .= Date_Calc::dayOfWeek($this->day,$this->month,$this->year);
489 break;
490 case "U":
491 $output .= Date_Calc::weekOfYear($this->day,$this->month,$this->year);
492 break;
493 case "y":
494 $output .= substr($this->year,2,2);
495 break;
496 case "Y":
497 $output .= $this->year;
498 break;
499 case "Z":
500 $output .= $this->tz->inDaylightTime($this) ? $this->tz->getDSTShortName() : $this->tz->getShortName();
501 break;
502 case "%":
503 $output .= "%";
504 break;
505 default:
506 $output .= $char.$nextchar;
507 }
508 $strpos++;
509 } else {
510 $output .= $char;
511 }
512 }
513 return $output;
514
515 }
516
517 // }}}
518 // {{{ getTime()
519
520 /**
521 * Get this date/time in Unix time() format
522 *
523 * Get a representation of this date in Unix time() format. This may only be
524 * valid for dates from 1970 to ~2038.
525 *
526 * @access public
527 * @return int number of seconds since the unix epoch
528 */
529 function getTime()
530 {
531 return $this->getDate(DATE_FORMAT_UNIXTIME);
532 }
533
534 // }}}
535 // {{{ setTZ()
536
537 /**
538 * Sets the time zone of this Date
539 *
540 * Sets the time zone of this date with the given
541 * Date_TimeZone object. Does not alter the date/time,
542 * only assigns a new time zone. For conversion, use
543 * convertTZ().
544 *
545 * @access public
546 * @param object Date_TimeZone $tz the Date_TimeZone object to use, if called
547 * with a paramater that is not a Date_TimeZone object, will fall through to
548 * setTZbyID().
549 */
550 function setTZ($tz)
551 {
552 if(is_a($tz, 'Date_Timezone')) {
553 $this->tz = $tz;
554 } else {
555 $this->setTZbyID($tz);
556 }
557 }
558
559 // }}}
560 // {{{ setTZbyID()
561
562 /**
563 * Sets the time zone of this date with the given time zone id
564 *
565 * Sets the time zone of this date with the given
566 * time zone id, or to the system default if the
567 * given id is invalid. Does not alter the date/time,
568 * only assigns a new time zone. For conversion, use
569 * convertTZ().
570 *
571 * @access public
572 * @param string id a time zone id
573 */
574 function setTZbyID($id)
575 {
576 if (Date_TimeZone::isValidID($id)) {
577 $this->tz = new Date_TimeZone($id);
578 } else {
579 $this->tz = Date_TimeZone::getDefault();
580 }
581 }
582
583 // }}}
584 // {{{ inDaylightTime()
585
586 /**
587 * Tests if this date/time is in DST
588 *
589 * Returns true if daylight savings time is in effect for
590 * this date in this date's time zone. See Date_TimeZone::inDaylightTime()
591 * for compatability information.
592 *
593 * @access public
594 * @return boolean true if DST is in effect for this date
595 */
596 function inDaylightTime()
597 {
598 return $this->tz->inDaylightTime($this);
599 }
600
601 // }}}
602 // {{{ toUTC()
603
604 /**
605 * Converts this date to UTC and sets this date's timezone to UTC
606 *
607 * Converts this date to UTC and sets this date's timezone to UTC
608 *
609 * @access public
610 */
611 function toUTC()
612 {
613 if ($this->tz->getOffset($this) > 0) {
614 $this->subtractSeconds(intval($this->tz->getOffset($this) / 1000));
615 } else {
616 $this->addSeconds(intval(abs($this->tz->getOffset($this)) / 1000));
617 }
618 $this->tz = new Date_TimeZone('UTC');
619 }
620
621 // }}}
622 // {{{ convertTZ()
623
624 /**
625 * Converts this date to a new time zone
626 *
627 * Converts this date to a new time zone.
628 * WARNING: This may not work correctly if your system does not allow
629 * putenv() or if localtime() does not work in your environment. See
630 * Date::TimeZone::inDaylightTime() for more information.
631 *
632 * @access public
633 * @param object Date_TimeZone $tz the Date::TimeZone object for the conversion time zone
634 */
635 function convertTZ($tz)
636 {
637 // convert to UTC
638 if ($this->tz->getOffset($this) > 0) {
639 $this->subtractSeconds(intval(abs($this->tz->getOffset($this)) / 1000));
640 } else {
641 $this->addSeconds(intval(abs($this->tz->getOffset($this)) / 1000));
642 }
643 // convert UTC to new timezone
644 if ($tz->getOffset($this) > 0) {
645 $this->addSeconds(intval(abs($tz->getOffset($this)) / 1000));
646 } else {
647 $this->subtractSeconds(intval(abs($tz->getOffset($this)) / 1000));
648 }
649 $this->tz = $tz;
650 }
651
652 // }}}
653 // {{{ convertTZbyID()
654
655 /**
656 * Converts this date to a new time zone, given a valid time zone ID
657 *
658 * Converts this date to a new time zone, given a valid time zone ID
659 * WARNING: This may not work correctly if your system does not allow
660 * putenv() or if localtime() does not work in your environment. See
661 * Date::TimeZone::inDaylightTime() for more information.
662 *
663 * @access public
664 * @param string id a time zone id
665 */
666 function convertTZbyID($id)
667 {
668 if (Date_TimeZone::isValidID($id)) {
669 $tz = new Date_TimeZone($id);
670 } else {
671 $tz = Date_TimeZone::getDefault();
672 }
673 $this->convertTZ($tz);
674 }
675
676 // }}}
677 // {{{ toUTCbyOffset()
678
679 function toUTCbyOffset($offset)
680 {
681 if ($offset == "Z" || $offset == "+00:00" || $offset == "+0000") {
682 $this->toUTC();
683 return true;
684 }
685
686 if (preg_match('/([\+\-])(\d{2}):?(\d{2})/', $offset, $regs)) {
687 // convert offset to seconds
688 $hours = (int) isset($regs[2])?$regs[2]:0;
689 $mins = (int) isset($regs[3])?$regs[3]:0;
690 $offset = ($hours * 3600) + ($mins * 60);
691
692 if (isset($regs[1]) && $regs[1] == "-") {
693 $offset *= -1;
694 }
695
696 if ($offset > 0) {
697 $this->subtractSeconds(intval($offset));
698 } else {
699 $this->addSeconds(intval(abs($offset)));
700 }
701
702 $this->tz = new Date_TimeZone('UTC');
703 return true;
704 }
705
706 return false;
707 }
708
709 // }}}
710 // {{{ addSeconds()
711
712 /**
713 * Adds a given number of seconds to the date
714 *
715 * Adds a given number of seconds to the date
716 *
717 * @access public
718 * @param int $sec the number of seconds to add
719 */
720 function addSeconds($sec)
721 {
722 settype($sec, 'int');
723
724 // Negative value given.
725 if ($sec < 0) {
726 $this->subtractSeconds(abs($sec));
727 return;
728 }
729
730 $this->addSpan(new Date_Span($sec));
731 }
732
733 // }}}
734 // {{{ addSpan()
735
736 /**
737 * Adds a time span to the date
738 *
739 * Adds a time span to the date
740 *
741 * @access public
742 * @param object Date_Span $span the time span to add
743 */
744 function addSpan($span)
745 {
746 if (!is_a($span, 'Date_Span')) {
747 return;
748 }
749
750 $this->second += $span->second;
751 if ($this->second >= 60) {
752 $this->minute++;
753 $this->second -= 60;
754 }
755
756 $this->minute += $span->minute;
757 if ($this->minute >= 60) {
758 $this->hour++;
759 if ($this->hour >= 24) {
760 list($this->year, $this->month, $this->day) =
761 sscanf(Date_Calc::nextDay($this->day, $this->month, $this->year), "%04s%02s%02s");
762 $this->hour -= 24;
763 }
764 $this->minute -= 60;
765 }
766
767 $this->hour += $span->hour;
768 if ($this->hour >= 24) {
769 list($this->year, $this->month, $this->day) =
770 sscanf(Date_Calc::nextDay($this->day, $this->month, $this->year), "%04s%02s%02s");
771 $this->hour -= 24;
772 }
773
774 $d = Date_Calc::dateToDays($this->day, $this->month, $this->year);
775 $d += $span->day;
776
777 list($this->year, $this->month, $this->day) =
778 sscanf(Date_Calc::daysToDate($d), "%04s%02s%02s");
779 $this->year = intval($this->year);
780 $this->month = intval($this->month);
781 $this->day = intval($this->day);
782 }
783
784 // }}}
785 // {{{ subtractSeconds()
786
787 /**
788 * Subtracts a given number of seconds from the date
789 *
790 * Subtracts a given number of seconds from the date
791 *
792 * @access public
793 * @param int $sec the number of seconds to subtract
794 */
795 function subtractSeconds($sec)
796 {
797 settype($sec, 'int');
798
799 // Negative value given.
800 if ($sec < 0) {
801 $this->addSeconds(abs($sec));
802 return;
803 }
804
805 $this->subtractSpan(new Date_Span($sec));
806 }
807
808 // }}}
809 // {{{ subtractSpan()
810
811 /**
812 * Subtracts a time span to the date
813 *
814 * Subtracts a time span to the date
815 *
816 * @access public
817 * @param object Date_Span $span the time span to subtract
818 */
819 function subtractSpan($span)
820 {
821 if (!is_a($span, 'Date_Span')) {
822 return;
823 }
824 if ($span->isEmpty()) {
825 return;
826 }
827
828 $this->second -= $span->second;
829 if ($this->second < 0) {
830 $this->minute--;
831 $this->second += 60;
832 }
833
834 $this->minute -= $span->minute;
835 if ($this->minute < 0) {
836 $this->hour--;
837 if ($this->hour < 0) {
838 list($this->year, $this->month, $this->day) =
839 sscanf(Date_Calc::prevDay($this->day, $this->month, $this->year), "%04s%02s%02s");
840 $this->hour += 24;
841 }
842 $this->minute += 60;
843 }
844
845 $this->hour -= $span->hour;
846 if ($this->hour < 0) {
847 list($this->year, $this->month, $this->day) =
848 sscanf(Date_Calc::prevDay($this->day, $this->month, $this->year), "%04s%02s%02s");
849 $this->hour += 24;
850 }
851
852 $d = Date_Calc::dateToDays($this->day, $this->month, $this->year);
853 $d -= $span->day;
854
855 list($this->year, $this->month, $this->day) =
856 sscanf(Date_Calc::daysToDate($d), "%04s%02s%02s");
857 $this->year = intval($this->year);
858 $this->month = intval($this->month);
859 $this->day = intval($this->day);
860 }
861
862 // }}}
863 // {{{ compare()
864
865 /**
866 * Compares two dates
867 *
868 * Compares two dates. Suitable for use
869 * in sorting functions.
870 *
871 * @access public
872 * @param object Date $d1 the first date
873 * @param object Date $d2 the second date
874 * @return int 0 if the dates are equal, -1 if d1 is before d2, 1 if d1 is after d2
875 */
876 function compare($d1, $d2)
877 {
878 $d1->convertTZ(new Date_TimeZone('UTC'));
879 $d2->convertTZ(new Date_TimeZone('UTC'));
880 $days1 = Date_Calc::dateToDays($d1->day, $d1->month, $d1->year);
881 $days2 = Date_Calc::dateToDays($d2->day, $d2->month, $d2->year);
882 if ($days1 < $days2) return -1;
883 if ($days1 > $days2) return 1;
884 if ($d1->hour < $d2->hour) return -1;
885 if ($d1->hour > $d2->hour) return 1;
886 if ($d1->minute < $d2->minute) return -1;
887 if ($d1->minute > $d2->minute) return 1;
888 if ($d1->second < $d2->second) return -1;
889 if ($d1->second > $d2->second) return 1;
890 return 0;
891 }
892
893 // }}}
894 // {{{ before()
895
896 /**
897 * Test if this date/time is before a certain date/time
898 *
899 * Test if this date/time is before a certain date/time
900 *
901 * @access public
902 * @param object Date $when the date to test against
903 * @return boolean true if this date is before $when
904 */
905 function before($when)
906 {
907 if (Date::compare($this,$when) == -1) {
908 return true;
909 } else {
910 return false;
911 }
912 }
913
914 // }}}
915 // {{{ after()
916
917 /**
918 * Test if this date/time is after a certian date/time
919 *
920 * Test if this date/time is after a certian date/time
921 *
922 * @access public
923 * @param object Date $when the date to test against
924 * @return boolean true if this date is after $when
925 */
926 function after($when)
927 {
928 if (Date::compare($this,$when) == 1) {
929 return true;
930 } else {
931 return false;
932 }
933 }
934
935 // }}}
936 // {{{ equals()
937
938 /**
939 * Test if this date/time is exactly equal to a certian date/time
940 *
941 * Test if this date/time is exactly equal to a certian date/time
942 *
943 * @access public
944 * @param object Date $when the date to test against
945 * @return boolean true if this date is exactly equal to $when
946 */
947 function equals($when)
948 {
949 if (Date::compare($this,$when) == 0) {
950 return true;
951 } else {
952 return false;
953 }
954 }
955
956 // }}}
957 // {{{ isFuture()
958
959 /**
960 * Determine if this date is in the future
961 *
962 * Determine if this date is in the future
963 *
964 * @access public
965 * @return boolean true if this date is in the future
966 */
967 function isFuture()
968 {
969 $now = new Date();
970 if ($this->after($now)) {
971 return true;
972 } else {
973 return false;
974 }
975 }
976
977 // }}}
978 // {{{ isPast()
979
980 /**
981 * Determine if this date is in the past
982 *
983 * Determine if this date is in the past
984 *
985 * @access public
986 * @return boolean true if this date is in the past
987 */
988 function isPast()
989 {
990 $now = new Date();
991 if ($this->before($now)) {
992 return true;
993 } else {
994 return false;
995 }
996 }
997
998 // }}}
999 // {{{ isLeapYear()
1000
1001 /**
1002 * Determine if the year in this date is a leap year
1003 *
1004 * Determine if the year in this date is a leap year
1005 *
1006 * @access public
1007 * @return boolean true if this year is a leap year
1008 */
1009 function isLeapYear()
1010 {
1011 return Date_Calc::isLeapYear($this->year);
1012 }
1013
1014 // }}}
1015 // {{{ getJulianDate()
1016
1017 /**
1018 * Get the Julian date for this date
1019 *
1020 * Get the Julian date for this date
1021 *
1022 * @access public
1023 * @return int the Julian date
1024 */
1025 function getJulianDate()
1026 {
1027 return Date_Calc::julianDate($this->day, $this->month, $this->year);
1028 }
1029
1030 // }}}
1031 // {{{ getDayOfWeek()
1032
1033 /**
1034 * Gets the day of the week for this date
1035 *
1036 * Gets the day of the week for this date (0=Sunday)
1037 *
1038 * @access public
1039 * @return int the day of the week (0=Sunday)
1040 */
1041 function getDayOfWeek()
1042 {
1043 return Date_Calc::dayOfWeek($this->day, $this->month, $this->year);
1044 }
1045
1046 // }}}
1047 // {{{ getWeekOfYear()
1048
1049 /**
1050 * Gets the week of the year for this date
1051 *
1052 * Gets the week of the year for this date
1053 *
1054 * @access public
1055 * @return int the week of the year
1056 */
1057 function getWeekOfYear()
1058 {
1059 return Date_Calc::weekOfYear($this->day, $this->month, $this->year);
1060 }
1061
1062 // }}}
1063 // {{{ getQuarterOfYear()
1064
1065 /**
1066 * Gets the quarter of the year for this date
1067 *
1068 * Gets the quarter of the year for this date
1069 *
1070 * @access public
1071 * @return int the quarter of the year (1-4)
1072 */
1073 function getQuarterOfYear()
1074 {
1075 return Date_Calc::quarterOfYear($this->day, $this->month, $this->year);
1076 }
1077
1078 // }}}
1079 // {{{ getDaysInMonth()
1080
1081 /**
1082 * Gets number of days in the month for this date
1083 *
1084 * Gets number of days in the month for this date
1085 *
1086 * @access public
1087 * @return int number of days in this month
1088 */
1089 function getDaysInMonth()
1090 {
1091 return Date_Calc::daysInMonth($this->month, $this->year);
1092 }
1093
1094 // }}}
1095 // {{{ getWeeksInMonth()
1096
1097 /**
1098 * Gets the number of weeks in the month for this date
1099 *
1100 * Gets the number of weeks in the month for this date
1101 *
1102 * @access public
1103 * @return int number of weeks in this month
1104 */
1105 function getWeeksInMonth()
1106 {
1107 return Date_Calc::weeksInMonth($this->month, $this->year);
1108 }
1109
1110 // }}}
1111 // {{{ getDayName()
1112
1113 /**
1114 * Gets the full name or abbriviated name of this weekday
1115 *
1116 * Gets the full name or abbriviated name of this weekday
1117 *
1118 * @access public
1119 * @param boolean $abbr abbrivate the name
1120 * @return string name of this day
1121 */
1122 function getDayName($abbr = false, $length = 3)
1123 {
1124 if ($abbr) {
1125 return Date_Calc::getWeekdayAbbrname($this->day, $this->month, $this->year, $length);
1126 } else {
1127 return Date_Calc::getWeekdayFullname($this->day, $this->month, $this->year);
1128 }
1129 }
1130
1131 // }}}
1132 // {{{ getMonthName()
1133
1134 /**
1135 * Gets the full name or abbriviated name of this month
1136 *
1137 * Gets the full name or abbriviated name of this month
1138 *
1139 * @access public
1140 * @param boolean $abbr abbrivate the name
1141 * @return string name of this month
1142 */
1143 function getMonthName($abbr = false)
1144 {
1145 if ($abbr) {
1146 return Date_Calc::getMonthAbbrname($this->month);
1147 } else {
1148 return Date_Calc::getMonthFullname($this->month);
1149 }
1150 }
1151
1152 // }}}
1153 // {{{ getNextDay()
1154
1155 /**
1156 * Get a Date object for the day after this one
1157 *
1158 * Get a Date object for the day after this one.
1159 * The time of the returned Date object is the same as this time.
1160 *
1161 * @access public
1162 * @return object Date Date representing the next day
1163 */
1164 function getNextDay()
1165 {
1166 $day = Date_Calc::nextDay($this->day, $this->month, $this->year, "%Y-%m-%d");
1167 $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
1168 $newDate = new Date();
1169 $newDate->setDate($date);
1170 return $newDate;
1171 }
1172
1173 // }}}
1174 // {{{ getPrevDay()
1175
1176 /**
1177 * Get a Date object for the day before this one
1178 *
1179 * Get a Date object for the day before this one.
1180 * The time of the returned Date object is the same as this time.
1181 *
1182 * @access public
1183 * @return object Date Date representing the previous day
1184 */
1185 function getPrevDay()
1186 {
1187 $day = Date_Calc::prevDay($this->day, $this->month, $this->year, "%Y-%m-%d");
1188 $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
1189 $newDate = new Date();
1190 $newDate->setDate($date);
1191 return $newDate;
1192 }
1193
1194 // }}}
1195 // {{{ getNextWeekday()
1196
1197 /**
1198 * Get a Date object for the weekday after this one
1199 *
1200 * Get a Date object for the weekday after this one.
1201 * The time of the returned Date object is the same as this time.
1202 *
1203 * @access public
1204 * @return object Date Date representing the next weekday
1205 */
1206 function getNextWeekday()
1207 {
1208 $day = Date_Calc::nextWeekday($this->day, $this->month, $this->year, "%Y-%m-%d");
1209 $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
1210 $newDate = new Date();
1211 $newDate->setDate($date);
1212 return $newDate;
1213 }
1214
1215 // }}}
1216 // {{{ getPrevWeekday()
1217
1218 /**
1219 * Get a Date object for the weekday before this one
1220 *
1221 * Get a Date object for the weekday before this one.
1222 * The time of the returned Date object is the same as this time.
1223 *
1224 * @access public
1225 * @return object Date Date representing the previous weekday
1226 */
1227 function getPrevWeekday()
1228 {
1229 $day = Date_Calc::prevWeekday($this->day, $this->month, $this->year, "%Y-%m-%d");
1230 $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
1231 $newDate = new Date();
1232 $newDate->setDate($date);
1233 return $newDate;
1234 }
1235
1236 // }}}
1237 // {{{ getYear()
1238
1239 /**
1240 * Returns the year field of the date object
1241 *
1242 * Returns the year field of the date object
1243 *
1244 * @access public
1245 * @return int the year
1246 */
1247 function getYear()
1248 {
1249 return (int)$this->year;
1250 }
1251
1252 // }}}
1253 // {{{ getMonth()
1254
1255 /**
1256 * Returns the month field of the date object
1257 *
1258 * Returns the month field of the date object
1259 *
1260 * @access public
1261 * @return int the month
1262 */
1263 function getMonth()
1264 {
1265 return (int)$this->month;
1266 }
1267
1268 // }}}
1269 // {{{ getDay()
1270
1271 /**
1272 * Returns the day field of the date object
1273 *
1274 * Returns the day field of the date object
1275 *
1276 * @access public
1277 * @return int the day
1278 */
1279 function getDay()
1280 {
1281 return (int)$this->day;
1282 }
1283
1284 // }}}
1285 // {{{ getHour()
1286
1287 /**
1288 * Returns the hour field of the date object
1289 *
1290 * Returns the hour field of the date object
1291 *
1292 * @access public
1293 * @return int the hour
1294 */
1295 function getHour()
1296 {
1297 return $this->hour;
1298 }
1299
1300 // }}}
1301 // {{{ getMinute()
1302
1303 /**
1304 * Returns the minute field of the date object
1305 *
1306 * Returns the minute field of the date object
1307 *
1308 * @access public
1309 * @return int the minute
1310 */
1311 function getMinute()
1312 {
1313 return $this->minute;
1314 }
1315
1316 // }}}
1317 // {{{ getSecond()
1318
1319 /**
1320 * Returns the second field of the date object
1321 *
1322 * Returns the second field of the date object
1323 *
1324 * @access public
1325 * @return int the second
1326 */
1327 function getSecond()
1328 {
1329 return $this->second;
1330 }
1331
1332 // }}}
1333 // {{{ setYear()
1334
1335 /**
1336 * Set the year field of the date object
1337 *
1338 * Set the year field of the date object, invalid years (not 0-9999) are set to 0.
1339 *
1340 * @access public
1341 * @param int $y the year
1342 */
1343 function setYear($y)
1344 {
1345 if ($y < 0 || $y > 9999) {
1346 $this->year = 0;
1347 } else {
1348 $this->year = $y;
1349 }
1350 }
1351
1352 // }}}
1353 // {{{ setMonth()
1354
1355 /**
1356 * Set the month field of the date object
1357 *
1358 * Set the month field of the date object, invalid months (not 1-12) are set to 1.
1359 *
1360 * @access public
1361 * @param int $m the month
1362 */
1363 function setMonth($m)
1364 {
1365 if ($m < 1 || $m > 12) {
1366 $this->month = 1;
1367 } else {
1368 $this->month = $m;
1369 }
1370 }
1371
1372 // }}}
1373 // {{{ setDay()
1374
1375 /**
1376 * Set the day field of the date object
1377 *
1378 * Set the day field of the date object, invalid days (not 1-31) are set to 1.
1379 *
1380 * @access public
1381 * @param int $d the day
1382 */
1383 function setDay($d)
1384 {
1385 if ($d > 31 || $d < 1) {
1386 $this->day = 1;
1387 } else {
1388 $this->day = $d;
1389 }
1390 }
1391
1392 // }}}
1393 // {{{ setHour()
1394
1395 /**
1396 * Set the hour field of the date object
1397 *
1398 * Set the hour field of the date object in 24-hour format.
1399 * Invalid hours (not 0-23) are set to 0.
1400 *
1401 * @access public
1402 * @param int $h the hour
1403 */
1404 function setHour($h)
1405 {
1406 if ($h > 23 || $h < 0) {
1407 $this->hour = 0;
1408 } else {
1409 $this->hour = $h;
1410 }
1411 }
1412
1413 // }}}
1414 // {{{ setMinute()
1415
1416 /**
1417 * Set the minute field of the date object
1418 *
1419 * Set the minute field of the date object, invalid minutes (not 0-59) are set to 0.
1420 *
1421 * @access public
1422 * @param int $m the minute
1423 */
1424 function setMinute($m)
1425 {
1426 if ($m > 59 || $m < 0) {
1427 $this->minute = 0;
1428 } else {
1429 $this->minute = $m;
1430 }
1431 }
1432
1433 // }}}
1434 // {{{ setSecond()
1435
1436 /**
1437 * Set the second field of the date object
1438 *
1439 * Set the second field of the date object, invalid seconds (not 0-59) are set to 0.
1440 *
1441 * @access public
1442 * @param int $s the second
1443 */
1444 function setSecond($s) {
1445 if ($s > 59 || $s < 0) {
1446 $this->second = 0;
1447 } else {
1448 $this->second = $s;
1449 }
1450 }
1451
1452 // }}}
1453 }
1454
1455 // }}}
1456
1457 /*
1458 * Local variables:
1459 * mode: php
1460 * tab-width: 4
1461 * c-basic-offset: 4
1462 * c-hanging-comment-ender-p: nil
1463 * End:
1464 */
1465 ?>