home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 April / CMCD0404.ISO / Software / Freeware / Programare / dotproject / lib / PEAR / Date / Span.php < prev    next >
PHP Script  |  2003-05-29  |  31KB  |  956 lines

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