Source for file jDateTime.class.php

Documentation is available at jDateTime.class.php

  1. <?php
  2. /**
  3. @package     jelix
  4. @subpackage  utils
  5. @author      GĂ©rald Croes, Laurent Jouanneau
  6. @contributor Laurent Jouanneau, Julien Issler
  7. @contributor Loic Mathaud
  8. @contributor Florian Hatat
  9. @contributor Emmanuel Hesry, Brice G.
  10. @contributor Hadrien Lanneau <hadrien@over-blog.com>
  11. @copyright   2005-2011 Laurent Jouanneau
  12. @copyright   2007 Loic Mathaud
  13. @copyright   2007-2008 Florian Hatat
  14. @copyright   2001-2005 CopixTeam, GeraldCroes, Laurent Jouanneau
  15. @copyright   2008-2011 Julien Issler
  16. @copyright   2009 Emmanuel Hesry
  17. @copyright   2010 Hadrien Lanneau, 2011 Brice G.
  18. *
  19. *  This class was get originally from the Copix project (CopixDate.lib.php, Copix 2.3dev20050901, http://www.copix.org)
  20. *  Only few lines of code are still copyrighted 2001-2005 CopixTeam (LGPL licence).
  21. *  Initial authors of this Copix classes are Gerald Croes and Laurent Jouanneau,
  22. *  and this class was adapted/improved for Jelix by Laurent Jouanneau
  23. *
  24. @link        http://www.jelix.org
  25. @licence     http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public Licence, see LICENCE file
  26. */
  27.  
  28. // on windows plateform, this function doesn't exist.
  29. if(!function_exists('strptime')){
  30.     /**
  31.      * @ignore
  32.      */
  33.     function strptime $strdate$format ){
  34.         // It's not a full compatibility with strptime of PHP5.1, but it is
  35.         // enough for our needs
  36.         $plop array'S'=>'tm_sec''M'=>'tm_min''H'=>'tm_hour',
  37.             'd'=>'tm_mday''m'=>'tm_mon''Y'=>'tm_year');
  38.  
  39.         $regexp preg_quote($format'/');
  40.         $regexp str_replace(
  41.                 array('%d','%m','%Y','%H','%M','%S'),
  42.                 array('(?P<tm_mday>\d{2})','(?P<tm_mon>\d{2})',
  43.                       '(?P<tm_year>\d{4})','(?P<tm_hour>\d{2})',
  44.                       '(?P<tm_min>\d{2})','(?P<tm_sec>\d{2})'),
  45.                 $regexp);
  46.         if(preg_match('/^'.$regexp.'$/'$strdate$m)){
  47.             $result=array('tm_sec'=>0,'tm_min'=>0,'tm_hour'=>0,'tm_mday'=>0,'tm_mon'=>0,'tm_year'=>0,'tm_wday'=>0,'tm_yday'=>0,'unparsed'=>'');
  48.             foreach($m as $key => $value){
  49.                 if(!isset($result[$key])){
  50.                     continue;
  51.                 }
  52.                 $result[$keyintval($value);
  53.                 switch($key){
  54.                 case 'tm_mon':
  55.                     $result[$key]--;
  56.                     break;
  57.                 case 'tm_year':
  58.                     $result[$key-= 1900;
  59.                     break;
  60.                 default:
  61.                     break;
  62.                 }
  63.             }
  64.             return $result;
  65.         }
  66.         return false;
  67.     }
  68. }
  69.  
  70.  
  71. /**
  72.  * Utility to manipulate dates and convert date format
  73.  * @package     jelix
  74.  * @subpackage  utils
  75.  * @todo PHP53 : replace the use of strptime by date_parse_from_format
  76.  */
  77. class jDateTime {
  78.     public $day;
  79.     public $month;
  80.     public $year;
  81.     public $hour;
  82.     public $minute;
  83.     public $second;
  84.  
  85.     public $defaultFormat = 11;
  86.  
  87.     const LANG_DFORMAT=10;
  88.     const LANG_DTFORMAT=11;
  89.     const LANG_TFORMAT=12;
  90.     const LANG_SHORT_DTFORMAT=13;
  91.     const LANG_SHORT_TFORMAT=14;
  92.     const DB_DFORMAT=20;
  93.     const DB_DTFORMAT=21;
  94.     const DB_TFORMAT=22;
  95.     const ISO8601_FORMAT=40;
  96.     const TIMESTAMP_FORMAT=50;
  97.     const RFC822_FORMAT=60;
  98.     const RFC2822_FORMAT=61;
  99.     const FULL_LANG_DATE=62;
  100.  
  101.     /**
  102.      *
  103.      */
  104.     function __construct($year=0$month=0$day=0$hour=0$minute=0$second=0){
  105.         $this->year = $year;
  106.         $this->month = $month;
  107.         $this->day = $day;
  108.         $this->hour = $hour;
  109.         $this->minute = $minute;
  110.         $this->second = $second;
  111.  
  112.         if(!$this->_check())
  113.         {
  114.           throw new jException('jelix~errors.datetime.invalid',
  115.               array($this->year$this->month$this->day,
  116.                 $this->hour$this->minute$this->second));
  117.         }
  118.     }
  119.  
  120.     /**
  121.      * Checks if the current jDateTime object is a valid gregorian date/time
  122.      * @return bool true if the date/time are valid.
  123.      */
  124.     private function _check({
  125.         // Only check the date if it is defined (eg. day, month and year are
  126.         // strictly positive).
  127.         if($this->day > && $this->month > && $this->year > 0
  128.             && !checkdate($this->month$this->day$this->year))
  129.         {
  130.             return false;
  131.         }
  132.         if(!(($this->second >= 0&& ($this->second < 60)
  133.             && ($this->minute >= 0&& ($this->minute < 60)
  134.             && ($this->hour >= 0&& ($this->hour < 24)))
  135.         {
  136.             return false;
  137.         }
  138.         return true;
  139.     }
  140.  
  141.      /**
  142.      * Check if jDateTime is "null" (all values egals to 0)
  143.      *
  144.      * @return boolean 
  145.      * @author Hadrien Lanneau (hadrien at over-blog dot com)
  146.      ***/
  147.     public function isNull({
  148.         return ($this->year === && $this->month === && $this->day === && $this->hour == && $this->minute == && $this->second == 0);
  149.     }
  150.  
  151.     /**
  152.      * Convert the date to a string format
  153.      * @param int $format one of the class constant xxx_FORMAT, or -1 if it should use the default format
  154.      * @return string the string date
  155.      * @see jDateTime:$defaultFormat
  156.      */
  157.     function toString($format=-1){
  158.         if($format==-1)
  159.             $format $this->defaultFormat;
  160.  
  161.         $str='';
  162.         switch($format){
  163.            case self::LANG_DFORMAT:
  164.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  165.                $lf jLocale::get('jelix~format.date');
  166.                $str date($lf$t);
  167.                break;
  168.            case self::LANG_DTFORMAT:
  169.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  170.                $lf jLocale::get('jelix~format.datetime');
  171.                $str date($lf$t);
  172.                break;
  173.            case self::LANG_TFORMAT:
  174.                $t mktime $this->hour$this->minute,$this->second 0);
  175.                $lf jLocale::get('jelix~format.time');
  176.                $str date($lf$t);
  177.                break;
  178.            case self::LANG_SHORT_DTFORMAT:
  179.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  180.                $lf jLocale::get('jelix~format.short_datetime');
  181.                $str date($lf$t);
  182.                break;
  183.            case self::LANG_SHORT_TFORMAT:
  184.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  185.                $lf jLocale::get('jelix~format.short_time');
  186.                $str date($lf$t);
  187.                break;
  188.            case self::DB_DFORMAT:
  189.                $str sprintf('%04d-%02d-%02d'$this->year$this->month$this->day);
  190.                break;
  191.            case self::DB_DTFORMAT:
  192.                $str sprintf('%04d-%02d-%02d %02d:%02d:%02d'$this->year$this->month$this->day$this->hour$this->minute$this->second);
  193.                break;
  194.            case self::DB_TFORMAT:
  195.                $str sprintf('%02d:%02d:%02d'$this->hour$this->minute$this->second);
  196.                break;
  197.            case self::ISO8601_FORMAT:
  198.                $str sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ'$this->year$this->month$this->day$this->hour$this->minute$this->second);
  199.                break;
  200.            case self::TIMESTAMP_FORMAT:
  201.                $str =(string) mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  202.                break;
  203.            case self::RFC822_FORMAT:
  204.            case self::RFC2822_FORMAT:
  205.                $str date('r'mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year ));
  206.                break;
  207.            case self::FULL_LANG_DATE:
  208.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  209.                // month translation
  210.                $month jLocale::get('jelix~date_time.month.'.date('m',$t).'.label');
  211.                // day translation
  212.                $day jLocale::get('jelix~date_time.day.'.date('w',$t).'.label');
  213.                // get the date formatting
  214.                $lf jLocale::get('jelix~format.date_full');
  215.                // get the ordinal format of the day in the month especially for the English format (1st, 2nd, 3rd and th for the others)
  216.                $ordinal jLocale::get('jelix~date_time.day.'.$this->day.'.ordinal');
  217.                // put all this in the right order using the formatting string
  218.                $str sprintf($lf$day$this->day$ordinal$month$this->year);
  219.                break;
  220.         }
  221.        return $str;
  222.     }
  223.  
  224.     /**
  225.      * read a string to extract date values
  226.      * @param string $str the string date
  227.      * @param int $format one of the class constant xxx_FORMAT, or -1 if it should use the default format
  228.      * @see jDateTime:$defaultFormat
  229.      */
  230.     function setFromString($str,$format=-1){
  231.         if($format==-1){
  232.             $format $this->defaultFormat;
  233.         }
  234.         $this->year = 0;
  235.         $this->month = 0;
  236.         $this->day = 0;
  237.         $this->hour = 0;
  238.         $this->minute = 0;
  239.         $this->second = 0;
  240.         $ok=false;
  241.  
  242.         switch($format){
  243.            case self::LANG_DFORMAT:
  244.                $lf jLocale::get('jelix~format.date_st');
  245.                if($res strptime $str$lf )){
  246.                    $ok=true;
  247.                    $this->year = $res['tm_year']+1900;
  248.                    $this->month = $res['tm_mon'+1;
  249.                    $this->day = $res['tm_mday'];
  250.                }
  251.                break;
  252.            case self::LANG_DTFORMAT:
  253.                $lf jLocale::get('jelix~format.datetime_st');
  254.                if($res strptime $str$lf )){
  255.                    $ok=true;
  256.                    $this->year = $res['tm_year'1900;
  257.                    $this->month = $res['tm_mon'1;
  258.                    $this->day = $res['tm_mday'];
  259.                    $this->hour = $res['tm_hour'];
  260.                    $this->minute = $res['tm_min'];
  261.                    $this->second = $res['tm_sec'];
  262.                }
  263.                break;
  264.            case self::LANG_TFORMAT:
  265.                $lf jLocale::get('jelix~format.time_st');
  266.                if($res strptime $str$lf )){
  267.                    $ok=true;
  268.                    $this->hour = $res['tm_hour'];
  269.                    $this->minute = $res['tm_min'];
  270.                    $this->second = $res['tm_sec'];
  271.                }
  272.                break;
  273.            case self::LANG_SHORT_TFORMAT:
  274.                $lf jLocale::get('jelix~format.short_time_st');
  275.                if($res strptime $str$lf )){
  276.                    $ok=true;
  277.                    $this->hour = $res['tm_hour'];
  278.                    $this->minute = $res['tm_min'];
  279.                    $this->second = 0;
  280.                }
  281.                break;
  282.            case self::LANG_SHORT_DTFORMAT:
  283.                $lf jLocale::get('jelix~format.short_datetime_st');
  284.                if($res strptime $str$lf )){
  285.                    $ok=true;
  286.                    $this->year = $res['tm_year'1900;
  287.                    $this->month = $res['tm_mon'1;
  288.                    $this->day = $res['tm_mday'];
  289.                    $this->hour = $res['tm_hour'];
  290.                    $this->minute = $res['tm_min'];
  291.                }
  292.                break;
  293.            case self::DB_DFORMAT:
  294.                if($res strptime$str"%Y-%m-%d" )){
  295.                    $ok=true;
  296.                    $this->year = $res['tm_year'1900;
  297.                    $this->month = $res['tm_mon'1;
  298.                    $this->day = $res['tm_mday'];
  299.                }
  300.                break;
  301.            case self::DB_DTFORMAT:
  302.                if($res strptime$str"%Y-%m-%d %H:%M:%S" )){
  303.                    $ok=true;
  304.                    $this->year = $res['tm_year'1900;
  305.                    $this->month = $res['tm_mon'1;
  306.                    $this->day = $res['tm_mday'];
  307.                    $this->hour = $res['tm_hour'];
  308.                    $this->minute = $res['tm_min'];
  309.                    $this->second = $res['tm_sec'];
  310.                }
  311.                break;
  312.            case self::DB_TFORMAT:
  313.                if($res strptime$str"%H:%M:%S" )){
  314.                    $ok=true;
  315.                    $this->hour = $res['tm_hour'];
  316.                    $this->minute = $res['tm_min'];
  317.                    $this->second = $res['tm_sec'];
  318.                }
  319.                break;
  320.            case self::ISO8601_FORMAT:
  321.                if($ok=preg_match('/^(\d{4})(?:\-(\d{2})(?:\-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{2,3}))?)?(Z|([+\-])(\d{2}):(\d{2})))?)?)?$/'$str$match)){
  322.                     $c count($match)-1;
  323.                     $this->year = intval($match[1]);
  324.                     if($c<2break;
  325.                     $this->month = intval($match[2]);
  326.                     if($c<3break;
  327.                     $this->day = intval($match[3]);
  328.                     if($c<4break;
  329.                     $this->hour = intval($match[4]);
  330.                     $this->minute = intval($match[5]);
  331.                     if($match[6!= ''$this->second = intval($match[6]);
  332.                     if($match[8!= 'Z'){
  333.                         $d new jDuration(array('hour'=>$match[10],'minute'=>$match[11]));
  334.                         if($match[9== '+')
  335.                             $this->sub($d);
  336.                         else
  337.                             $this->add($d);
  338.                     }
  339.                }
  340.                break;
  341.            case self::TIMESTAMP_FORMAT:
  342.                $ok=true;
  343.                $t getdate intval($str) );
  344.                $this->year = $t['year'];
  345.                $this->month = $t['mon'];
  346.                $this->day = $t['mday'];
  347.                $this->hour = $t['hours'];
  348.                $this->minute = $t['minutes'];
  349.                $this->second = $t['seconds'];
  350.                break;
  351.            case self::RFC822_FORMAT:
  352.            case self::RFC2822_FORMAT:
  353.                // Note the "x" modifier, otherwise the pattern would look like
  354.                // obfuscated code.
  355.                $regexp "/^
  356.                      (?: (?P<nday> Mon | Tue | Wed | Thu | Fri | Sat | Sun) , )? \s+
  357.                      (?P<day>\d{1,2}) \s+
  358.                      (?P<nmonth> Jan | Feb | Mar | Apr | May | Jun |
  359.                                Jul | Aug | Sep | Oct | Nov | Dec) \s+
  360.                      (?P<year>\d{4}) \s+
  361.                      (?P<hour>\d{2}) : (?P<minute>\d{2}) (?: : (?P<second>\d{2}))? \s+
  362.                      (?P<tzsign>[+-]) (?P<tzhour>\d{2}) (?P<tzminute>\d{2})$/x";
  363.  
  364.                $english_months array("Jan""Feb""Mar""Apr""May""Jun",
  365.                    "Jul""Aug""Sep""Oct""Nov""Dec");
  366.  
  367.                $match array("year" => 0"month" => 0"day" => 0,
  368.                    "hour" => 0"minute" => 0"second" => 0"tzsign" => "+",
  369.                    "tzhour" => 0"tzminute" => 0);
  370.  
  371.                if($ok preg_match($regexp$str$match)){
  372.                    $this->year = intval($match['year']);
  373.                    $this->month = array_search($match['nmonth']$english_months1;
  374.                    $this->day = intval($match['day']);
  375.                    $this->hour = intval($match['hour']);
  376.                    $this->minute = intval($match['minute']);
  377.                    $this->second = intval($match['second']);
  378.  
  379.                    // Adjust according to the timezone, so that the stored time
  380.                    // corresponds to UTC.
  381.                    $tz new jDuration(array('hour'=>intval($match['tzhour']),
  382.                        'minute'=>intval($match['tzminute'])));
  383.                    if($match['tzsign'== '+'){
  384.                        $this->sub($tz);
  385.                    }
  386.                    else{
  387.                        $this->add($tz);
  388.                    }
  389.                }
  390.                break;
  391.         }
  392.  
  393.         return $ok && $this->_check();
  394.     }
  395.  
  396.     /**
  397.      * Add a duration to the date.
  398.      * You can specify the duration in a jDuration object or give each value of
  399.      * the duration.
  400.      * @param jDuration/int $year the duration value or a year with 4 digits
  401.      * @param int $month month with 2 digits
  402.      * @param int $day day with 2 digits
  403.      * @param int $hour hour with 2 digits
  404.      * @param int $minute minute with 2 digits
  405.      * @param int $second second with 2 digits
  406.      */
  407.     public function add($year$month=0$day=0$hour=0$minute=0$second=0{
  408.         if ($year instanceof jDuration{
  409.             $dt $year;
  410.         else {
  411.             $dt new jDuration(array("year" => $year"month" => $month,
  412.                 "day" => $day"hour" => $hour"minute" => $minute,
  413.                 "second" => $second));
  414.         }
  415.         $t mktime($this->hour$this->minute$this->second + $dt->seconds,
  416.              $this->month + $dt->months$this->day + $dt->days$this->year);
  417.  
  418.         $t getdate ($t);
  419.         $this->year = $t['year'];
  420.         $this->month = $t['mon'];
  421.         $this->day = $t['mday'];
  422.         $this->hour = $t['hours'];
  423.         $this->minute = $t['minutes'];
  424.         $this->second = $t['seconds'];
  425.     }
  426.  
  427.     /**
  428.      * substract a <b>duration</b> to the date
  429.      * You can specify the duration in a jDuration object or give each value of
  430.      * the duration.
  431.      * @param jDuration/int $year the duration value or a year with 4 digits
  432.      * @param int $month month with 2 digits
  433.      * @param int $day day with 2 digits
  434.      * @param int $hour hour with 2 digits
  435.      * @param int $minute minute with 2 digits
  436.      * @param int $second second with 2 digits
  437.      */
  438.     public function sub($year$month=0$day=0$hour=0$minute=0$second=0{
  439.         if ($year instanceof jDuration{
  440.             $dt $year;
  441.         else {
  442.             $dt new jDuration(array("year" => $year"month" => $month,
  443.                 "day" => $day"hour" => $hour"minute" => $minute,
  444.                 "second" => $second));
  445.         }
  446.         $dt->mult(-1);
  447.         $this->add($dt);
  448.     }
  449.  
  450.     /**
  451.      * to know the duration between two dates.
  452.      * @param jDateTime $dt  the date on which a sub will be made with the date on the current object
  453.      * @param bool $absolute 
  454.      * @return jDuration a jDuration object
  455.      */
  456.     public function durationTo($dt$absolute=true){
  457.         if($absolute){
  458.             $t gmmktime($dt->hour$dt->minute$dt->second,
  459.                 $dt->month$dt->day$dt->year)
  460.                 - gmmktime($this->hour$this->minute$this->second,
  461.                     $this->month$this->day$this->year);
  462.             return new jDuration($t);
  463.         }
  464.         else{
  465.             return new jDuration(array(
  466.                 "year" => $dt->year $this->year,
  467.                 "month" => $dt->month $this->month,
  468.                 "day" => $dt->day $this-> day,
  469.                 "hour" => $dt->hour $this->hour,
  470.                 "minute" => $dt->minute $this->minute,
  471.                 "second" => $dt->second $this->second
  472.             ));
  473.         }
  474.     }
  475.  
  476.     /**
  477.      * Compare two date
  478.      * @param jDateTime $dt the date to compare
  479.      * @return integer -1 if $dt > $this, 0 if $dt = $this, 1 if $dt < $this
  480.      */
  481.     public function compareTo($dt){
  482.         $fields=array('year','month','day','hour','minute','second');
  483.         foreach($fields as $field){
  484.             if($dt->$field $this->$field)
  485.                 return -1;
  486.             if($dt->$field $this->$field)
  487.                 return 1;
  488.         }
  489.         return 0;
  490.     }
  491.  
  492.     /**
  493.     * Set date to current datetime
  494.     */
  495.     public function now({
  496.         $this->year = intval(date('Y'));
  497.         $this->month = intval(date('m'));
  498.         $this->day = intval(date('d'));
  499.         $this->hour = intval(date('H'));
  500.         $this->minute = intval(date('i'));
  501.         $this->second = intval(date('s'));
  502.     }
  503.  
  504.  
  505.     /**
  506.     * Substract a date with another
  507.     * @param jDateTime $date 
  508.     * @return jDateTime 
  509.     * @author Hadrien Lanneau <hadrien@over-blog.com>
  510.     * @since 1.2
  511.     */
  512.     public function substract($date null{
  513.         if (!$date{
  514.             $date new jDateTime();
  515.             $date->now();
  516.         }
  517.  
  518.         $newDate new jDateTime();
  519.  
  520.         $items array(
  521.                 'second',
  522.                 'minute',
  523.                 'hour',
  524.                 'day',
  525.                 'month',
  526.                 'year'
  527.             );
  528.  
  529.         foreach ($items as $k => $i{
  530.             $newDate->{$i$date->{$i$this->{$i};
  531.             if ($newDate->{$i0{
  532.                 switch ($i{
  533.                     case 'second':
  534.                     case 'minute':
  535.                         $sub 60;
  536.                         break;
  537.                     case 'hour':
  538.                         $sub 24;
  539.                         break;
  540.                     case 'day':
  541.                         switch ($this->month{
  542.                             // Month with 31 days
  543.                             case 1:
  544.                             case 3:
  545.                             case 5:
  546.                             case 7:
  547.                             case 8:
  548.                             case 10:
  549.                             case 12:
  550.                                 $sub 31;
  551.                                 break;
  552.                             // Month with 30 days
  553.                             case 4:
  554.                             case 6:
  555.                             case 9:
  556.                             case 11:
  557.                                 $sub 30;
  558.                                 break;
  559.                             // February
  560.                             case 2:
  561.                                 if ($this->year == and
  562.                                         !(
  563.                                                 $this->year 100 == and
  564.                                                 $this->year 400 != 0
  565.                                         )) {
  566.                                     // Bissextile
  567.                                     $sub 29;
  568.                                 }
  569.                                 else {
  570.                                    $sub 28;
  571.                                 }
  572.                                 break;
  573.                         }
  574.                         break;
  575.                     case 'month':
  576.                         $sub 12;
  577.                         break;
  578.                     default:
  579.                         $sub 0;
  580.                 }
  581.                 $newDate->{$iabs($sub $newDate->{$i});
  582.                 if (isset($items[$k+1])) {
  583.                     $newDate->{$items[$k+1]}--;
  584.                 }
  585.             }
  586.         }
  587.         return $newDate;
  588.     }
  589. }

Documentation generated on Wed, 24 Sep 2014 21:58:22 +0200 by phpDocumentor 1.4.3