fix image text
[pear] / Date / Span.php
1 <?php\r
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */\r
3 \r
4 // {{{ Header\r
5 \r
6 /**\r
7  * Generic time span handling class for PEAR\r
8  *\r
9  * PHP versions 4 and 5\r
10  *\r
11  * LICENSE:\r
12  *\r
13  * Copyright (c) 1997-2005 Leandro Lucarella, Pierre-Alain Joye\r
14  * All rights reserved.\r
15  *\r
16  * Redistribution and use in source and binary forms, with or without\r
17  * modification, are permitted under the terms of the BSD License.\r
18  *\r
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
30  * POSSIBILITY OF SUCH DAMAGE.\r
31  *\r
32  * @category   Date and Time\r
33  * @package    Date\r
34  * @author     Leandro Lucarella <llucax@php.net>\r
35  * @author     Pierre-Alain Joye <pajoye@php.net>\r
36  * @copyright  1997-2006 Leandro Lucarella, Pierre-Alain Joye\r
37  * @license    http://www.opensource.org/licenses/bsd-license.php\r
38  *             BSD License\r
39  * @version    CVS: $Id: Span.php,v 1.9 2006/11/21 17:38:15 firman Exp $\r
40  * @link       http://pear.php.net/package/Date\r
41  * @since      File available since Release 1.4\r
42  */\r
43 \r
44 // }}}\r
45 // {{{ Includes\r
46 \r
47 /**\r
48  * Get the Date class\r
49  */\r
50 require_once 'Date.php';\r
51 \r
52 /**\r
53  * Get the Date_Calc class\r
54  */\r
55 require_once 'Date/Calc.php';\r
56 \r
57 // }}}\r
58 // {{{ Constants\r
59 \r
60 /**\r
61  * Non Numeric Separated Values (NNSV) Input Format.\r
62  *\r
63  * Input format guessed from something like this:\r
64  * days<sep>hours<sep>minutes<sep>seconds\r
65  * Where <sep> is any quantity of non numeric chars. If no values are\r
66  * given, time span is set to zero, if one value is given, it's used for\r
67  * hours, if two values are given it's used for hours and minutes and if\r
68  * three values are given, it's used for hours, minutes and seconds.<br>\r
69  * Examples:<br>\r
70  * ''                   -> 0, 0, 0, 0 (days, hours, minutes, seconds)<br>\r
71  * '12'                 -> 0, 12, 0, 0\r
72  * '12.30'              -> 0, 12, 30, 0<br>\r
73  * '12:30:18'           -> 0, 12, 30, 18<br>\r
74  * '3-12-30-18'         -> 3, 12, 30, 18<br>\r
75  * '3 days, 12-30-18'   -> 3, 12, 30, 18<br>\r
76  * '12:30 with 18 secs' -> 0, 12, 30, 18<br>\r
77  *\r
78  * @const int\r
79  */\r
80 define('DATE_SPAN_INPUT_FORMAT_NNSV', 1);\r
81 \r
82 // }}}\r
83 // {{{ Global Variables\r
84 \r
85 /**\r
86  * Default time format when converting to a string.\r
87  *\r
88  * @global string\r
89  */\r
90 $GLOBALS['_DATE_SPAN_FORMAT']  = '%C';\r
91 \r
92 /**\r
93  * Default time format when converting from a string.\r
94  *\r
95  * @global mixed\r
96  */\r
97 $GLOBALS['_DATE_SPAN_INPUT_FORMAT'] = DATE_SPAN_INPUT_FORMAT_NNSV;\r
98 \r
99 // }}}\r
100 // {{{ Class: Date_Span\r
101 \r
102 /**\r
103  * Generic time span handling class for PEAR\r
104  *\r
105  * @author     Leandro Lucarella <llucax@php.net>\r
106  * @author     Pierre-Alain Joye <pajoye@php.net>\r
107  * @copyright  1997-2006 Leandro Lucarella, Pierre-Alain Joye\r
108  * @license    http://www.opensource.org/licenses/bsd-license.php\r
109  *             BSD License\r
110  * @version    Release: 1.4.7\r
111  * @link       http://pear.php.net/package/Date\r
112  * @since      Class available since Release 1.4\r
113  */\r
114 class Date_Span\r
115 {\r
116     // {{{ Properties\r
117 \r
118     /**\r
119      * @var int\r
120      */\r
121     var $day;\r
122 \r
123     /**\r
124      * @var int\r
125      */\r
126     var $hour;\r
127 \r
128     /**\r
129      * @var int\r
130      */\r
131     var $minute;\r
132 \r
133     /**\r
134      * @var int\r
135      */\r
136     var $second;\r
137 \r
138     // }}}\r
139     // {{{ Constructor\r
140 \r
141     /**\r
142      * Constructor.\r
143      *\r
144      * Creates the time span object calling the set() method.\r
145      *\r
146      * @param  mixed $time   Time span expression.\r
147      * @param  mixed $format Format string to set it from a string or the\r
148      *                       second date set it from a date diff.\r
149      *\r
150      * @see    set()\r
151      * @access public\r
152      */\r
153     function __construct($time = 0, $format = null)\r
154     {\r
155         $this->set($time, $format);\r
156     }\r
157 \r
158     // }}}\r
159     // {{{ set()\r
160 \r
161     /**\r
162      * Set the time span to a new value in a 'smart' way.\r
163      *\r
164      * Sets the time span depending on the argument types, calling\r
165      * to the appropriate setFromXxx() method.\r
166      *\r
167      * @param  mixed $time   Time span expression.\r
168      * @param  mixed $format Format string to set it from a string or the\r
169      *                       second date set it from a date diff.\r
170      *\r
171      * @return bool  true on success.\r
172      *\r
173      * @see    setFromObject()\r
174      * @see    setFromArray()\r
175      * @see    setFromString()\r
176      * @see    setFromSeconds()\r
177      * @see    setFromDateDiff()\r
178      * @access public\r
179      */\r
180     function set($time = 0, $format = null)\r
181     {\r
182         if (is_a($time, 'date_span')) {\r
183             return $this->copy($time);\r
184         } elseif (is_a($time, 'date') and is_a($format, 'date')) {\r
185             return $this->setFromDateDiff($time, $format);\r
186         } elseif (is_array($time)) {\r
187             return $this->setFromArray($time);\r
188         } elseif (is_string($time)) {\r
189             return $this->setFromString($time, $format);\r
190         } elseif (is_int($time)) {\r
191             return $this->setFromSeconds($time);\r
192         } else {\r
193             return $this->setFromSeconds(0);\r
194         }\r
195     }\r
196 \r
197     // }}}\r
198     // {{{ setFromArray()\r
199 \r
200     /**\r
201      * Set the time span from an array.\r
202      *\r
203      * Set the time span from an array. Any value can be a float (but it\r
204      * has no sense in seconds), for example array(23.5, 20, 0) is\r
205      * interpreted as 23 hours, .5*60 + 20 = 50 minutes and 0 seconds.\r
206      *\r
207      * @param  array $time Items are counted from right to left. First\r
208      *                     item is for seconds, second for minutes, third\r
209      *                     for hours and fourth for days. If there are\r
210      *                     less items than 4, zero (0) is assumed for the\r
211      *                     absent values.\r
212      *\r
213      * @return bool  True on success.\r
214      *\r
215      * @access public\r
216      */\r
217     function setFromArray($time)\r
218     {\r
219         if (!is_array($time)) {\r
220             return false;\r
221         }\r
222         $tmp1 = new Date_Span;\r
223         if (!$tmp1->setFromSeconds(@array_pop($time))) {\r
224             return false;\r
225         }\r
226         $tmp2 = new Date_Span;\r
227         if (!$tmp2->setFromMinutes(@array_pop($time))) {\r
228             return false;\r
229         }\r
230         $tmp1->add($tmp2);\r
231         if (!$tmp2->setFromHours(@array_pop($time))) {\r
232             return false;\r
233         }\r
234         $tmp1->add($tmp2);\r
235         if (!$tmp2->setFromDays(@array_pop($time))) {\r
236             return false;\r
237         }\r
238         $tmp1->add($tmp2);\r
239         return $this->copy($tmp1);\r
240     }\r
241 \r
242     // }}}\r
243     // {{{ setFromString()\r
244 \r
245     /**\r
246      * Set the time span from a string based on an input format.\r
247      *\r
248      * Set the time span from a string based on an input format. This is\r
249      * some like a mix of format() method and sscanf() PHP function. The\r
250      * error checking and validation of this function is very primitive,\r
251      * so you should be carefull when using it with unknown $time strings.\r
252      * With this method you are assigning day, hour, minute and second\r
253      * values, and the last values are used. This means that if you use\r
254      * something like setFromString('10, 20', '%H, %h') your time span\r
255      * would be 20 hours long. Allways remember that this method set\r
256      * <b>all</b> the values, so if you had a $time span 30 minutes long\r
257      * and you make $time->setFromString('20 hours', '%H hours'), $time\r
258      * span would be 20 hours long (and not 20 hours and 30 minutes).\r
259      * Input format options:<br>\r
260      *  <code>%C</code> Days with time, same as "%D, %H:%M:%S".<br>\r
261      *  <code>%d</code> Total days as a float number\r
262      *                  (2 days, 12 hours = 2.5 days).<br>\r
263      *  <code>%D</code> Days as a decimal number.<br>\r
264      *  <code>%e</code> Total hours as a float number\r
265      *                  (1 day, 2 hours, 30 minutes = 26.5 hours).<br>\r
266      *  <code>%f</code> Total minutes as a float number\r
267      *                  (2 minutes, 30 seconds = 2.5 minutes).<br>\r
268      *  <code>%g</code> Total seconds as a decimal number\r
269      *                  (2 minutes, 30 seconds = 90 seconds).<br>\r
270      *  <code>%h</code> Hours as decimal number.<br>\r
271      *  <code>%H</code> Hours as decimal number limited to 2 digits.<br>\r
272      *  <code>%m</code> Minutes as a decimal number.<br>\r
273      *  <code>%M</code> Minutes as a decimal number limited to 2 digits.<br>\r
274      *  <code>%n</code> Newline character (\n).<br>\r
275      *  <code>%p</code> Either 'am' or 'pm' depending on the time. If 'pm'\r
276      *                  is detected it adds 12 hours to the resulting time\r
277      *                  span (without any checks). This is case\r
278      *                  insensitive.<br>\r
279      *  <code>%r</code> Time in am/pm notation, same as "%H:%M:%S %p".<br>\r
280      *  <code>%R</code> Time in 24-hour notation, same as "%H:%M".<br>\r
281      *  <code>%s</code> Seconds as a decimal number.<br>\r
282      *  <code>%S</code> Seconds as a decimal number limited to 2 digits.<br>\r
283      *  <code>%t</code> Tab character (\t).<br>\r
284      *  <code>%T</code> Current time equivalent, same as "%H:%M:%S".<br>\r
285      *  <code>%%</code> Literal '%'.<br>\r
286      *\r
287      * @param  string $time   String from where to get the time span\r
288      *                        information.\r
289      * @param  string $format Format string.\r
290      *\r
291      * @return bool   True on success.\r
292      *\r
293      * @access public\r
294      */\r
295     function setFromString($time, $format = null)\r
296     {\r
297         if (is_null($format)) {\r
298             $format = $GLOBALS['_DATE_SPAN_INPUT_FORMAT'];\r
299         }\r
300         // If format is a string, it parses the string format.\r
301         if (is_string($format)) {\r
302             $str = '';\r
303             $vars = array();\r
304             $pm = 'am';\r
305             $day = $hour = $minute = $second = 0;\r
306             for ($i = 0; $i < strlen($format); $i++) {\r
307                 $char = $format[$i];\r
308                 if ($char == '%') {\r
309                     $nextchar = $format[++$i];\r
310                     switch ($nextchar) {\r
311                         case 'c':\r
312                             $str .= '%d, %d:%d:%d';\r
313                             array_push(\r
314                                 $vars, 'day', 'hour', 'minute', 'second');\r
315                             break;\r
316                         case 'C':\r
317                             $str .= '%d, %2d:%2d:%2d';\r
318                             array_push(\r
319                                 $vars, 'day', 'hour', 'minute', 'second');\r
320                             break;\r
321                         case 'd':\r
322                             $str .= '%f';\r
323                             array_push($vars, 'day');\r
324                             break;\r
325                         case 'D':\r
326                             $str .= '%d';\r
327                             array_push($vars, 'day');\r
328                             break;\r
329                         case 'e':\r
330                             $str .= '%f';\r
331                             array_push($vars, 'hour');\r
332                             break;\r
333                         case 'f':\r
334                             $str .= '%f';\r
335                             array_push($vars, 'minute');\r
336                             break;\r
337                         case 'g':\r
338                             $str .= '%f';\r
339                             array_push($vars, 'second');\r
340                             break;\r
341                         case 'h':\r
342                             $str .= '%d';\r
343                             array_push($vars, 'hour');\r
344                             break;\r
345                         case 'H':\r
346                             $str .= '%2d';\r
347                             array_push($vars, 'hour');\r
348                             break;\r
349                         case 'm':\r
350                             $str .= '%d';\r
351                             array_push($vars, 'minute');\r
352                             break;\r
353                         case 'M':\r
354                             $str .= '%2d';\r
355                             array_push($vars, 'minute');\r
356                             break;\r
357                         case 'n':\r
358                             $str .= "\n";\r
359                             break;\r
360                         case 'p':\r
361                             $str .= '%2s';\r
362                             array_push($vars, 'pm');\r
363                             break;\r
364                         case 'r':\r
365                             $str .= '%2d:%2d:%2d %2s';\r
366                             array_push(\r
367                                 $vars, 'hour', 'minute', 'second', 'pm');\r
368                             break;\r
369                         case 'R':\r
370                             $str .= '%2d:%2d';\r
371                             array_push($vars, 'hour', 'minute');\r
372                             break;\r
373                         case 's':\r
374                             $str .= '%d';\r
375                             array_push($vars, 'second');\r
376                             break;\r
377                         case 'S':\r
378                             $str .= '%2d';\r
379                             array_push($vars, 'second');\r
380                             break;\r
381                         case 't':\r
382                             $str .= "\t";\r
383                             break;\r
384                         case 'T':\r
385                             $str .= '%2d:%2d:%2d';\r
386                             array_push($vars, 'hour', 'minute', 'second');\r
387                             break;\r
388                         case '%':\r
389                             $str .= "%";\r
390                             break;\r
391                         default:\r
392                             $str .= $char . $nextchar;\r
393                     }\r
394                 } else {\r
395                     $str .= $char;\r
396                 }\r
397             }\r
398             $vals = sscanf($time, $str);\r
399             foreach ($vals as $i => $val) {\r
400                 if (is_null($val)) {\r
401                     return false;\r
402                 }\r
403                 $$vars[$i] = $val;\r
404             }\r
405             if (strcasecmp($pm, 'pm') == 0) {\r
406                 $hour += 12;\r
407             } elseif (strcasecmp($pm, 'am') != 0) {\r
408                 return false;\r
409             }\r
410             $this->setFromArray(array($day, $hour, $minute, $second));\r
411         // If format is a integer, it uses a predefined format\r
412         // detection method.\r
413         } elseif (is_integer($format)) {\r
414             switch ($format) {\r
415                 case DATE_SPAN_INPUT_FORMAT_NNSV:\r
416                     $time = preg_split('/\D+/', $time);\r
417                     switch (count($time)) {\r
418                         case 0:\r
419                             return $this->setFromArray(\r
420                                 array(0, 0, 0, 0));\r
421                         case 1:\r
422                             return $this->setFromArray(\r
423                                 array(0, $time[0], 0, 0));\r
424                         case 2:\r
425                             return $this->setFromArray(\r
426                                 array(0, $time[0], $time[1], 0));\r
427                         case 3:\r
428                             return $this->setFromArray(\r
429                                 array(0, $time[0], $time[1], $time[2]));\r
430                         default:\r
431                             return $this->setFromArray($time);\r
432                     }\r
433                     break;\r
434             }\r
435         }\r
436         return false;\r
437     }\r
438 \r
439     // }}}\r
440     // {{{ setFromSeconds()\r
441 \r
442     /**\r
443      * Set the time span from a total number of seconds.\r
444      *\r
445      * @param  int  $seconds Total number of seconds.\r
446      *\r
447      * @return bool True on success.\r
448      *\r
449      * @access public\r
450      */\r
451     function setFromSeconds($seconds)\r
452     {\r
453         if ($seconds < 0) {\r
454             return false;\r
455         }\r
456         $sec  = intval($seconds);\r
457         $min  = floor($sec / 60);\r
458         $hour = floor($min / 60);\r
459         $day  = intval(floor($hour / 24));\r
460         $this->second = $sec % 60;\r
461         $this->minute = $min % 60;\r
462         $this->hour   = $hour % 24;\r
463         $this->day    = $day;\r
464         return true;\r
465     }\r
466 \r
467     // }}}\r
468     // {{{ setFromMinutes()\r
469 \r
470     /**\r
471      * Set the time span from a total number of minutes.\r
472      *\r
473      * @param  float $minutes Total number of minutes.\r
474      *\r
475      * @return bool  True on success.\r
476      *\r
477      * @access public\r
478      */\r
479     function setFromMinutes($minutes)\r
480     {\r
481         return $this->setFromSeconds(round($minutes * 60));\r
482     }\r
483 \r
484     // }}}\r
485     // {{{ setFromHours()\r
486 \r
487     /**\r
488      * Set the time span from a total number of hours.\r
489      *\r
490      * @param  float $hours Total number of hours.\r
491      *\r
492      * @return bool  True on success.\r
493      *\r
494      * @access public\r
495      */\r
496     function setFromHours($hours)\r
497     {\r
498         return $this->setFromSeconds(round($hours * 3600));\r
499     }\r
500 \r
501     // }}}\r
502     // {{{ setFromDays()\r
503 \r
504     /**\r
505      * Set the time span from a total number of days.\r
506      *\r
507      * @param  float $days Total number of days.\r
508      *\r
509      * @return bool  True on success.\r
510      *\r
511      * @access public\r
512      */\r
513     function setFromDays($days)\r
514     {\r
515         return $this->setFromSeconds(round($days * 86400));\r
516     }\r
517 \r
518     // }}}\r
519     // {{{ setFromDateDiff()\r
520 \r
521     /**\r
522      * Set the span from the elapsed time between two dates.\r
523      *\r
524      * Set the span from the elapsed time between two dates. The time span\r
525      * is allways positive, so the date's order is not important.\r
526      *\r
527      * @param  object Date $date1 First Date.\r
528      * @param  object Date $date2 Second Date.\r
529      *\r
530      * @return bool  True on success.\r
531      *\r
532      * @access public\r
533      */\r
534     function setFromDateDiff($date1, $date2)\r
535     {\r
536         if (!is_a($date1, 'date') or !is_a($date2, 'date')) {\r
537             return false;\r
538         }\r
539         $date1->toUTC();\r
540         $date2->toUTC();\r
541         if ($date1->after($date2)) {\r
542             list($date1, $date2) = array($date2, $date1);\r
543         }\r
544         $days = Date_Calc::dateDiff(\r
545             $date1->getDay(), $date1->getMonth(), $date1->getYear(),\r
546             $date2->getDay(), $date2->getMonth(), $date2->getYear()\r
547         );\r
548         $hours = $date2->getHour() - $date1->getHour();\r
549         $mins  = $date2->getMinute() - $date1->getMinute();\r
550         $secs  = $date2->getSecond() - $date1->getSecond();\r
551         $this->setFromSeconds(\r
552             $days * 86400 + $hours * 3600 + $mins * 60 + $secs\r
553         );\r
554         return true;\r
555     }\r
556 \r
557     // }}}\r
558     // {{{ copy()\r
559 \r
560     /**\r
561      * Set the time span from another time object.\r
562      *\r
563      * @param  object Date_Span $time Source time span object.\r
564      *\r
565      * @return bool   True on success.\r
566      *\r
567      * @access public\r
568      */\r
569     function copy($time)\r
570     {\r
571         if (is_a($time, 'date_span')) {\r
572             $this->second = $time->second;\r
573             $this->minute = $time->minute;\r
574             $this->hour   = $time->hour;\r
575             $this->day    = $time->day;\r
576             return true;\r
577         } else {\r
578             return false;\r
579         }\r
580     }\r
581 \r
582     // }}}\r
583     // {{{ format()\r
584 \r
585     /**\r
586      * Time span pretty printing (similar to Date::format()).\r
587      *\r
588      * Formats the time span in the given format, similar to\r
589      * strftime() and Date::format().<br>\r
590      * <br>\r
591      * Formatting options:<br>\r
592      *  <code>%C</code> Days with time, same as "%D, %H:%M:%S".<br>\r
593      *  <code>%d</code> Total days as a float number\r
594      *                  (2 days, 12 hours = 2.5 days).<br>\r
595      *  <code>%D</code> Days as a decimal number.<br>\r
596      *  <code>%e</code> Total hours as a float number\r
597      *                  (1 day, 2 hours, 30 minutes = 26.5 hours).<br>\r
598      *  <code>%E</code> Total hours as a decimal number\r
599      *                  (1 day, 2 hours, 40 minutes = 26 hours).<br>\r
600      *  <code>%f</code> Total minutes as a float number\r
601      *                  (2 minutes, 30 seconds = 2.5 minutes).<br>\r
602      *  <code>%F</code> Total minutes as a decimal number\r
603      *                  (1 hour, 2 minutes, 40 seconds = 62 minutes).<br>\r
604      *  <code>%g</code> Total seconds as a decimal number\r
605      *                  (2 minutes, 30 seconds = 90 seconds).<br>\r
606      *  <code>%h</code> Hours as decimal number (0 to 23).<br>\r
607      *  <code>%H</code> Hours as decimal number (00 to 23).<br>\r
608      *  <code>%i</code> Hours as decimal number on 12-hour clock\r
609      *                  (1 to 12).<br>\r
610      *  <code>%I</code> Hours as decimal number on 12-hour clock\r
611      *                  (01 to 12).<br>\r
612      *  <code>%m</code> Minutes as a decimal number (0 to 59).<br>\r
613      *  <code>%M</code> Minutes as a decimal number (00 to 59).<br>\r
614      *  <code>%n</code> Newline character (\n).<br>\r
615      *  <code>%p</code> Either 'am' or 'pm' depending on the time.<br>\r
616      *  <code>%P</code> Either 'AM' or 'PM' depending on the time.<br>\r
617      *  <code>%r</code> Time in am/pm notation, same as "%I:%M:%S %p".<br>\r
618      *  <code>%R</code> Time in 24-hour notation, same as "%H:%M".<br>\r
619      *  <code>%s</code> Seconds as a decimal number (0 to 59).<br>\r
620      *  <code>%S</code> Seconds as a decimal number (00 to 59).<br>\r
621      *  <code>%t</code> Tab character (\t).<br>\r
622      *  <code>%T</code> Current time equivalent, same as "%H:%M:%S".<br>\r
623      *  <code>%%</code> Literal '%'.<br>\r
624      *\r
625      * @param  string $format The format string for returned time span.\r
626      *\r
627      * @return string The time span in specified format.\r
628      *\r
629      * @access public\r
630      */\r
631     function format($format = null)\r
632     {\r
633         if (is_null($format)) {\r
634             $format = $GLOBALS['_DATE_SPAN_FORMAT'];\r
635         }\r
636         $output = '';\r
637         for ($i = 0; $i < strlen($format); $i++) {\r
638             $char = $format[$i];\r
639             if ($char == '%') {\r
640                 $nextchar = $format[++$i];\r
641                 switch ($nextchar) {\r
642                     case 'C':\r
643                         $output .= sprintf(\r
644                             '%d, %02d:%02d:%02d',\r
645                             $this->day,\r
646                             $this->hour,\r
647                             $this->minute,\r
648                             $this->second\r
649                         );\r
650                         break;\r
651                     case 'd':\r
652                         $output .= $this->toDays();\r
653                         break;\r
654                     case 'D':\r
655                         $output .= $this->day;\r
656                         break;\r
657                     case 'e':\r
658                         $output .= $this->toHours();\r
659                         break;\r
660                     case 'E':\r
661                         $output .= floor($this->toHours());\r
662                         break;\r
663                     case 'f':\r
664                         $output .= $this->toMinutes();\r
665                         break;\r
666                     case 'F':\r
667                         $output .= floor($this->toMinutes());\r
668                         break;\r
669                     case 'g':\r
670                         $output .= $this->toSeconds();\r
671                         break;\r
672                     case 'h':\r
673                         $output .= $this->hour;\r
674                         break;\r
675                     case 'H':\r
676                         $output .= sprintf('%02d', $this->hour);\r
677                         break;\r
678                     case 'i':\r
679                         $hour =\r
680                             ($this->hour + 1) > 12 ?\r
681                             $this->hour - 12 :\r
682                             $this->hour;\r
683                         $output .= ($hour == 0) ? 12 : $hour;\r
684                         break;\r
685                     case 'I':\r
686                         $hour =\r
687                             ($this->hour + 1) > 12 ?\r
688                             $this->hour - 12 :\r
689                             $this->hour;\r
690                         $output .= sprintf('%02d', $hour==0 ? 12 : $hour);\r
691                         break;\r
692                     case 'm':\r
693                         $output .= $this->minute;\r
694                         break;\r
695                     case 'M':\r
696                         $output .= sprintf('%02d',$this->minute);\r
697                         break;\r
698                     case 'n':\r
699                         $output .= "\n";\r
700                         break;\r
701                     case 'p':\r
702                         $output .= $this->hour >= 12 ? 'pm' : 'am';\r
703                         break;\r
704                     case 'P':\r
705                         $output .= $this->hour >= 12 ? 'PM' : 'AM';\r
706                         break;\r
707                     case 'r':\r
708                         $hour =\r
709                             ($this->hour + 1) > 12 ?\r
710                             $this->hour - 12 :\r
711                             $this->hour;\r
712                         $output .= sprintf(\r
713                             '%02d:%02d:%02d %s',\r
714                             $hour==0 ?  12 : $hour,\r
715                             $this->minute,\r
716                             $this->second,\r
717                             $this->hour >= 12 ? 'pm' : 'am'\r
718                         );\r
719                         break;\r
720                     case 'R':\r
721                         $output .= sprintf(\r
722                             '%02d:%02d', $this->hour, $this->minute\r
723                         );\r
724                         break;\r
725                     case 's':\r
726                         $output .= $this->second;\r
727                         break;\r
728                     case 'S':\r
729                         $output .= sprintf('%02d', $this->second);\r
730                         break;\r
731                     case 't':\r
732                         $output .= "\t";\r
733                         break;\r
734                     case 'T':\r
735                         $output .= sprintf(\r
736                             '%02d:%02d:%02d',\r
737                             $this->hour, $this->minute, $this->second\r
738                         );\r
739                         break;\r
740                     case '%':\r
741                         $output .= "%";\r
742                         break;\r
743                     default:\r
744                         $output .= $char . $nextchar;\r
745                 }\r
746             } else {\r
747                 $output .= $char;\r
748             }\r
749         }\r
750         return $output;\r
751     }\r
752 \r
753     // }}}\r
754     // {{{ toSeconds()\r
755 \r
756     /**\r
757      * Convert time span to seconds.\r
758      *\r
759      * @return int Time span as an integer number of seconds.\r
760      *\r
761      * @access public\r
762      */\r
763     function toSeconds()\r
764     {\r
765         return $this->day * 86400 + $this->hour * 3600 +\r
766             $this->minute * 60 + $this->second;\r
767     }\r
768 \r
769     // }}}\r
770     // {{{ toMinutes()\r
771 \r
772     /**\r
773      * Convert time span to minutes.\r
774      *\r
775      * @return float Time span as a decimal number of minutes.\r
776      *\r
777      * @access public\r
778      */\r
779     function toMinutes()\r
780     {\r
781         return $this->day * 1440 + $this->hour * 60 + $this->minute +\r
782             $this->second / 60;\r
783     }\r
784 \r
785     // }}}\r
786     // {{{ toHours()\r
787 \r
788     /**\r
789      * Convert time span to hours.\r
790      *\r
791      * @return float Time span as a decimal number of hours.\r
792      *\r
793      * @access public\r
794      */\r
795     function toHours()\r
796     {\r
797         return $this->day * 24 + $this->hour + $this->minute / 60 +\r
798             $this->second / 3600;\r
799     }\r
800 \r
801     // }}}\r
802     // {{{ toDays()\r
803 \r
804     /**\r
805      * Convert time span to days.\r
806      *\r
807      * @return float Time span as a decimal number of days.\r
808      *\r
809      * @access public\r
810      */\r
811     function toDays()\r
812     {\r
813         return $this->day + $this->hour / 24 + $this->minute / 1440 +\r
814             $this->second / 86400;\r
815     }\r
816 \r
817     // }}}\r
818     // {{{ add()\r
819 \r
820     /**\r
821      * Adds a time span.\r
822      *\r
823      * @param  object Date_Span $time Time span to add.\r
824      *\r
825      * @access public\r
826      */\r
827     function add($time)\r
828     {\r
829         return $this->setFromSeconds(\r
830             $this->toSeconds() + $time->toSeconds()\r
831         );\r
832     }\r
833 \r
834     // }}}\r
835     // {{{ substract()\r
836 \r
837     /**\r
838      * Subtracts a time span.\r
839      *\r
840      * Subtracts a time span. If the time span to subtract is larger\r
841      * than the original, the result is zero (there's no sense in\r
842      * negative time spans).\r
843      *\r
844      * @param  object Date_Span $time Time span to subtract.\r
845      *\r
846      * @access public\r
847      */\r
848     function subtract($time)\r
849     {\r
850         $sub = $this->toSeconds() - $time->toSeconds();\r
851         if ($sub < 0) {\r
852             $this->setFromSeconds(0);\r
853         } else {\r
854             $this->setFromSeconds($sub);\r
855         }\r
856     }\r
857 \r
858     // }}}\r
859     // {{{ equal()\r
860 \r
861     /**\r
862      * Tells if time span is equal to $time.\r
863      *\r
864      * @param  object Date_Span $time Time span to compare to.\r
865      *\r
866      * @return bool   True if the time spans are equal.\r
867      *\r
868      * @access public\r
869      */\r
870     function equal($time)\r
871     {\r
872         return $this->toSeconds() == $time->toSeconds();\r
873     }\r
874 \r
875     // }}}\r
876     // {{{ greaterEqual()\r
877 \r
878     /**\r
879      * Tells if this time span is greater or equal than $time.\r
880      *\r
881      * @param  object Date_Span $time Time span to compare to.\r
882      *\r
883      * @return bool   True if this time span is greater or equal than $time.\r
884      *\r
885      * @access public\r
886      */\r
887     function greaterEqual($time)\r
888     {\r
889         return $this->toSeconds() >= $time->toSeconds();\r
890     }\r
891 \r
892     // }}}\r
893     // {{{ lowerEqual()\r
894 \r
895     /**\r
896      * Tells if this time span is lower or equal than $time.\r
897      *\r
898      * @param  object Date_Span $time Time span to compare to.\r
899      *\r
900      * @return bool   True if this time span is lower or equal than $time.\r
901      *\r
902      * @access public\r
903      */\r
904     function lowerEqual($time)\r
905     {\r
906         return $this->toSeconds() <= $time->toSeconds();\r
907     }\r
908 \r
909     // }}}\r
910     // {{{ greater()\r
911 \r
912     /**\r
913      * Tells if this time span is greater than $time.\r
914      *\r
915      * @param  object Date_Span $time Time span to compare to.\r
916      *\r
917      * @return bool   True if this time span is greater than $time.\r
918      *\r
919      * @access public\r
920      */\r
921     function greater($time)\r
922     {\r
923         return $this->toSeconds() > $time->toSeconds();\r
924     }\r
925 \r
926     // }}}\r
927     // {{{ lower()\r
928 \r
929     /**\r
930      * Tells if this time span is lower than $time.\r
931      *\r
932      * @param  object Date_Span $time Time span to compare to.\r
933      *\r
934      * @return bool   True if this time span is lower than $time.\r
935      *\r
936      * @access public\r
937      */\r
938     function lower($time)\r
939     {\r
940         return $this->toSeconds() < $time->toSeconds();\r
941     }\r
942 \r
943     // }}}\r
944     // {{{ compare()\r
945 \r
946     /**\r
947      * Compares two time spans.\r
948      *\r
949      * Compares two time spans. Suitable for use in sorting functions.\r
950      *\r
951      * @param  object Date_Span $time1 The first time span.\r
952      * @param  object Date_Span $time2 The second time span.\r
953      *\r
954      * @return int    0 if the time spans are equal, -1 if time1 is lower\r
955      *                than time2, 1 if time1 is greater than time2.\r
956      *\r
957      * @static\r
958      * @access public\r
959      */\r
960     function compare($time1, $time2)\r
961     {\r
962         if ($time1->equal($time2)) {\r
963             return 0;\r
964         } elseif ($time1->lower($time2)) {\r
965             return -1;\r
966         } else {\r
967             return 1;\r
968         }\r
969     }\r
970 \r
971     // }}}\r
972     // {{{ isEmpty()\r
973 \r
974     /**\r
975      * Tells if the time span is empty (zero length).\r
976      *\r
977      * @return bool True is it's empty.\r
978      */\r
979     function isEmpty()\r
980     {\r
981         return !$this->day && !$this->hour && !$this->minute && !$this->second;\r
982     }\r
983 \r
984     // }}}\r
985     // {{{ setDefaultInputFormat()\r
986 \r
987     /**\r
988      * Set the default input format.\r
989      *\r
990      * @param  mixed $format New default input format.\r
991      *\r
992      * @return mixed Previous default input format.\r
993      *\r
994      * @static\r
995      */\r
996     function setDefaultInputFormat($format)\r
997     {\r
998         $old = $GLOBALS['_DATE_SPAN_INPUT_FORMAT'];\r
999         $GLOBALS['_DATE_SPAN_INPUT_FORMAT'] = $format;\r
1000         return $old;\r
1001     }\r
1002 \r
1003     // }}}\r
1004     // {{{ getDefaultInputFormat()\r
1005 \r
1006     /**\r
1007      * Get the default input format.\r
1008      *\r
1009      * @return mixed Default input format.\r
1010      *\r
1011      * @static\r
1012      */\r
1013     function getDefaultInputFormat()\r
1014     {\r
1015         return $GLOBALS['_DATE_SPAN_INPUT_FORMAT'];\r
1016     }\r
1017 \r
1018     // }}}\r
1019     // {{{ setDefaultFormat()\r
1020 \r
1021     /**\r
1022      * Set the default format.\r
1023      *\r
1024      * @param  mixed $format New default format.\r
1025      *\r
1026      * @return mixed Previous default format.\r
1027      *\r
1028      * @static\r
1029      */\r
1030     function setDefaultFormat($format)\r
1031     {\r
1032         $old = $GLOBALS['_DATE_SPAN_FORMAT'];\r
1033         $GLOBALS['_DATE_SPAN_FORMAT'] = $format;\r
1034         return $old;\r
1035     }\r
1036 \r
1037     // }}}\r
1038     // {{{ getDefaultFormat()\r
1039 \r
1040     /**\r
1041      * Get the default format.\r
1042      *\r
1043      * @return mixed Default format.\r
1044      *\r
1045      * @static\r
1046      */\r
1047     function getDefaultFormat()\r
1048     {\r
1049         return $GLOBALS['_DATE_SPAN_FORMAT'];\r
1050     }\r
1051 \r
1052     // }}}\r
1053     // {{{ __clone()\r
1054 \r
1055     /**\r
1056      * Returns a copy of the object (workarround for PHP5 forward compatibility).\r
1057      *\r
1058      * @return object Date_Span Copy of the object.\r
1059      */\r
1060     function __clone() {\r
1061         $c = get_class($this);\r
1062         $s = new $c;\r
1063         $s->day    = $this->day;\r
1064         $s->hour   = $this->hour;\r
1065         $s->minute = $this->minute;\r
1066         $s->second = $this->second;\r
1067         return $s;\r
1068     }\r
1069 \r
1070     // }}}\r
1071 }\r
1072 \r
1073 // }}}\r
1074 \r
1075 /*\r
1076  * Local variables:\r
1077  * mode: php\r
1078  * tab-width: 4\r
1079  * c-basic-offset: 4\r
1080  * c-hanging-comment-ender-p: nil\r
1081  * End:\r
1082  */\r
1083 ?>