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
  10. @contributor Hadrien Lanneau <hadrien@over-blog.com>
  11. @copyright   2005-2008 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
  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. #if PHP50
  29. if(!function_exists('strptime'))// existe depuis php 5.1
  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. #endif
  70.  
  71. /**
  72.  * Utility to manipulate dates and convert date format
  73.  * @package     jelix
  74.  * @subpackage  utils
  75.  */
  76. class jDateTime {
  77.     public $day;
  78.     public $month;
  79.     public $year;
  80.     public $hour;
  81.     public $minute;
  82.     public $second;
  83.  
  84.     public $defaultFormat = 11;
  85.  
  86.     const LANG_DFORMAT=10;
  87.     const LANG_DTFORMAT=11;
  88.     const LANG_TFORMAT=12;
  89.     const DB_DFORMAT=20;
  90.     const DB_DTFORMAT=21;
  91.     const DB_TFORMAT=22;
  92.     const ISO8601_FORMAT=40;
  93.     const TIMESTAMP_FORMAT=50;
  94.     const RFC822_FORMAT=60;
  95.     const RFC2822_FORMAT=61;
  96.     const FULL_LANG_DATE=62;
  97.  
  98.     /**
  99.      *
  100.      */
  101.     function __construct($year=0$month=0$day=0$hour=0$minute=0$second=0){
  102.         $this->year = $year;
  103.         $this->month = $month;
  104.         $this->day = $day;
  105.         $this->hour = $hour;
  106.         $this->minute = $minute;
  107.         $this->second = $second;
  108.  
  109.         if(!$this->_check())
  110.         {
  111.           throw new jException('jelix~errors.datetime.invalid',
  112.               array($this->year$this->month$this->day,
  113.                 $this->hour$this->minute$this->second));
  114.         }
  115.     }
  116.  
  117.     /**
  118.      * checks if the current jDateTime object is a valid gregorian date/time
  119.      * @return bool true if the date/time are valid.
  120.      */
  121.     private function _check({
  122.         // Only check the date if it is defined (eg. day, month and year are
  123.         // strictly positive).
  124.         if($this->day > && $this->month > && $this->year > 0
  125.             && !checkdate($this->month$this->day$this->year))
  126.         {
  127.             return false;
  128.         }
  129.         if(!(($this->second >= 0&& ($this->second < 60)
  130.             && ($this->minute >= 0&& ($this->minute < 60)
  131.             && ($this->hour >= 0&& ($this->hour < 24)))
  132.         {
  133.             return false;
  134.         }
  135.         return true;
  136.     }
  137.  
  138.      /**
  139.      * Check if jDateTime is "null" (all values egals to 0)
  140.      *
  141.      * @return boolean 
  142.      * @author Hadrien Lanneau (hadrien at over-blog dot com)
  143.      ***/
  144.     public function isNull({
  145.         return ($this->year === && $this->month === && $this->day === && $this->hour == && $this->minute == && $this->second == 0);
  146.     }
  147.  
  148.     /**
  149.      * convert the date to a string format
  150.      * @param int $format one of the class constant xxx_FORMAT, or -1 if it should use the default format
  151.      * @return string the string date
  152.      * @see jDateTime:$defaultFormat
  153.      */
  154.     function toString($format=-1){
  155.         if($format==-1)
  156.             $format $this->defaultFormat;
  157.  
  158.         $str='';
  159.         switch($format){
  160.            case self::LANG_DFORMAT:
  161.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  162.                $lf jLocale::get('jelix~format.date');
  163.                $str date($lf$t);
  164.                break;
  165.            case self::LANG_DTFORMAT:
  166.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  167.                $lf jLocale::get('jelix~format.datetime');
  168.                $str date($lf$t);
  169.                break;
  170.            case self::LANG_TFORMAT:
  171.                $t mktime $this->hour$this->minute,$this->second 0);
  172.                $lf jLocale::get('jelix~format.time');
  173.                $str date($lf$t);
  174.                break;
  175.            case self::DB_DFORMAT:
  176.                $str sprintf('%04d-%02d-%02d'$this->year$this->month$this->day);
  177.                break;
  178.            case self::DB_DTFORMAT:
  179.                $str sprintf('%04d-%02d-%02d %02d:%02d:%02d'$this->year$this->month$this->day$this->hour$this->minute$this->second);
  180.                break;
  181.            case self::DB_TFORMAT:
  182.                $str sprintf('%02d:%02d:%02d'$this->hour$this->minute$this->second);
  183.                break;
  184.            case self::ISO8601_FORMAT:
  185.                $str sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ'$this->year$this->month$this->day$this->hour$this->minute$this->second);
  186.                break;
  187.            case self::TIMESTAMP_FORMAT:
  188.                $str =(string) mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  189.                break;
  190.            case self::RFC822_FORMAT:
  191.            case self::RFC2822_FORMAT:
  192.                $str date('r'mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year ));
  193.                break;
  194.            case self::FULL_LANG_DATE:
  195.                $t mktime $this->hour$this->minute,$this->second $this->month$this->day$this->year );
  196.                // traduction du mois
  197.                $month jLocale::get('jelix~date_time.month.'.date('m',$t).'.label');
  198.                // traduction du jour
  199.                $day jLocale::get('jelix~date_time.day.'.date('w',$t).'.label');
  200.                // récupération du formatage de la date
  201.                $lf jLocale::get('jelix~format.date_full');
  202.                // récupération du format ordinal du jour dans le mois surtout pour le format en anglais (1st, 2nd, 3rd et th pour les autres
  203.                $ordinal jLocale::get('jelix~date_time.day.'.$this->day.'.ordinal');
  204.                // on mets le tout dans le bon ordre à l'aide de la chaine de formatage
  205.                $str sprintf($lf$day$this->day$ordinal$month$this->year);
  206.                break;
  207.         }
  208.        return $str;
  209.     }
  210.  
  211.     /**
  212.      * read a string to extract date values
  213.      * @param string $str the string date
  214.      * @param int $format one of the class constant xxx_FORMAT, or -1 if it should use the default format
  215.      * @see jDateTime:$defaultFormat
  216.      */
  217.     function setFromString($str,$format=-1){
  218.         if($format==-1){
  219.             $format $this->defaultFormat;
  220.         }
  221.         $this->year = 0;
  222.         $this->month = 0;
  223.         $this->day = 0;
  224.         $this->hour = 0;
  225.         $this->minute = 0;
  226.         $this->second = 0;
  227.         $ok=false;
  228.  
  229.         switch($format){
  230.            case self::LANG_DFORMAT:
  231.                $lf jLocale::get('jelix~format.date_st');
  232.                if($res strptime $str$lf )){
  233.                    $ok=true;
  234.                    $this->year = $res['tm_year']+1900;
  235.                    $this->month = $res['tm_mon'+1;
  236.                    $this->day = $res['tm_mday'];
  237.                }
  238.                break;
  239.            case self::LANG_DTFORMAT:
  240.                $lf jLocale::get('jelix~format.datetime_st');
  241.                if($res strptime $str$lf )){
  242.                    $ok=true;
  243.                    $this->year = $res['tm_year'1900;
  244.                    $this->month = $res['tm_mon'1;
  245.                    $this->day = $res['tm_mday'];
  246.                    $this->hour = $res['tm_hour'];
  247.                    $this->minute = $res['tm_min'];
  248.                    $this->second = $res['tm_sec'];
  249.                }
  250.                break;
  251.            case self::LANG_TFORMAT:
  252.                $lf jLocale::get('jelix~format.time_st');
  253.                if($res strptime $str$lf )){
  254.                    $ok=true;
  255.                    $this->hour = $res['tm_hour'];
  256.                    $this->minute = $res['tm_min'];
  257.                    $this->second = $res['tm_sec'];
  258.                }
  259.                break;
  260.            case self::DB_DFORMAT:
  261.                if($res strptime$str"%Y-%m-%d" )){
  262.                    $ok=true;
  263.                    $this->year = $res['tm_year'1900;
  264.                    $this->month = $res['tm_mon'1;
  265.                    $this->day = $res['tm_mday'];
  266.                }
  267.                break;
  268.            case self::DB_DTFORMAT:
  269.                if($res strptime$str"%Y-%m-%d %H:%M:%S" )){
  270.                    $ok=true;
  271.                    $this->year = $res['tm_year'1900;
  272.                    $this->month = $res['tm_mon'1;
  273.                    $this->day = $res['tm_mday'];
  274.                    $this->hour = $res['tm_hour'];
  275.                    $this->minute = $res['tm_min'];
  276.                    $this->second = $res['tm_sec'];
  277.                }
  278.                break;
  279.            case self::DB_TFORMAT:
  280.                if($res strptime$str"%H:%M:%S" )){
  281.                    $ok=true;
  282.                    $this->hour = $res['tm_hour'];
  283.                    $this->minute = $res['tm_min'];
  284.                    $this->second = $res['tm_sec'];
  285.                }
  286.                break;
  287.            case self::ISO8601_FORMAT:
  288.                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)){
  289.                     $c count($match)-1;
  290.                     $this->year = intval($match[1]);
  291.                     if($c<2break;
  292.                     $this->month = intval($match[2]);
  293.                     if($c<3break;
  294.                     $this->day = intval($match[3]);
  295.                     if($c<4break;
  296.                     $this->hour = intval($match[4]);
  297.                     $this->minute = intval($match[5]);
  298.                     if($match[6!= ''$this->second = intval($match[6]);
  299.                     if($match[8!= 'Z'){
  300.                         $d new jDuration(array('hour'=>$match[10],'minute'=>$match[11]));
  301.                         if($match[9== '+')
  302.                             $this->sub($d);
  303.                         else
  304.                             $this->add($d);
  305.                     }
  306.                }
  307.                break;
  308.            case self::TIMESTAMP_FORMAT:
  309.                $ok=true;
  310.                $t getdate intval($str) );
  311.                $this->year = $t['year'];
  312.                $this->month = $t['mon'];
  313.                $this->day = $t['mday'];
  314.                $this->hour = $t['hours'];
  315.                $this->minute = $t['minutes'];
  316.                $this->second = $t['seconds'];
  317.                break;
  318.            case self::RFC822_FORMAT:
  319.            case self::RFC2822_FORMAT:
  320.                // Note the "x" modifier, otherwise the pattern would look like
  321.                // obfuscated code.
  322.                $regexp "/^
  323.                      (?: (?P<nday> Mon | Tue | Wed | Thu | Fri | Sat | Sun) , )? \s+
  324.                      (?P<day>\d{1,2}) \s+
  325.                      (?P<nmonth> Jan | Feb | Mar | Apr | May | Jun |
  326.                                Jul | Aug | Sep | Oct | Nov | Dec) \s+
  327.                      (?P<year>\d{4}) \s+
  328.                      (?P<hour>\d{2}) : (?P<minute>\d{2}) (?: : (?P<second>\d{2}))? \s+
  329.                      (?P<tzsign>[+-]) (?P<tzhour>\d{2}) (?P<tzminute>\d{2})$/x";
  330.  
  331.                $english_months array("Jan""Feb""Mar""Apr""May""Jun",
  332.                    "Jul""Aug""Sep""Oct""Nov""Dec");
  333.  
  334.                $match array("year" => 0"month" => 0"day" => 0,
  335.                    "hour" => 0"minute" => 0"second" => 0"tzsign" => "+",
  336.                    "tzhour" => 0"tzminute" => 0);
  337.  
  338.                if($ok preg_match($regexp$str$match)){
  339.                    $this->year = intval($match['year']);
  340.                    $this->month = array_search($match['nmonth']$english_months1;
  341.                    $this->day = intval($match['day']);
  342.                    $this->hour = intval($match['hour']);
  343.                    $this->minute = intval($match['minute']);
  344.                    $this->second = intval($match['second']);
  345.  
  346.                    # Adjust according to the timezone, so that the stored time
  347.                    # corresponds to UTC.
  348.                    $tz new jDuration(array('hour'=>intval($match['tzhour']),
  349.                        'minute'=>intval($match['tzminute'])));
  350.                    if($match['tzsign'== '+'){
  351.                        $this->sub($tz);
  352.                    }
  353.                    else{
  354.                        $this->add($tz);
  355.                    }
  356.                }
  357.                break;
  358.         }
  359.  
  360.         return $ok && $this->_check();
  361.     }
  362.  
  363.     /**
  364.      * Add a duration to the date.
  365.      * You can specify the duration in a jDuration object or give each value of
  366.      * the duration.
  367.      * @param jDuration/int $year the duration value or a year with 4 digits
  368.      * @param int $month month with 2 digits
  369.      * @param int $day day with 2 digits
  370.      * @param int $hour hour with 2 digits
  371.      * @param int $minute minute with 2 digits
  372.      * @param int $second second with 2 digits
  373.      */
  374.     public function add($year$month=0$day=0$hour=0$minute=0$second=0{
  375.         if ($year instanceof jDuration{
  376.             $dt $year;
  377.         else {
  378.             $dt new jDuration(array("year" => $year"month" => $month,
  379.                 "day" => $day"hour" => $hour"minute" => $minute,
  380.                 "second" => $second));
  381.         }
  382.         $t mktime($this->hour$this->minute$this->second + $dt->seconds,
  383.              $this->month + $dt->months$this->day + $dt->days$this->year);
  384.  
  385.         $t getdate ($t);
  386.         $this->year = $t['year'];
  387.         $this->month = $t['mon'];
  388.         $this->day = $t['mday'];
  389.         $this->hour = $t['hours'];
  390.         $this->minute = $t['minutes'];
  391.         $this->second = $t['seconds'];
  392.     }
  393.  
  394.     /**
  395.      * substract a <b>duration</b> to the date
  396.      * You can specify the duration in a jDuration object or give each value of
  397.      * the duration.
  398.      * @param jDuration/int $year the duration value or a year with 4 digits
  399.      * @param int $month month with 2 digits
  400.      * @param int $day day with 2 digits
  401.      * @param int $hour hour with 2 digits
  402.      * @param int $minute minute with 2 digits
  403.      * @param int $second second with 2 digits
  404.      */
  405.     public function sub($year$month=0$day=0$hour=0$minute=0$second=0{
  406.         if ($year instanceof jDuration{
  407.             $dt $year;
  408.         else {
  409.             $dt new jDuration(array("year" => $year"month" => $month,
  410.                 "day" => $day"hour" => $hour"minute" => $minute,
  411.                 "second" => $second));
  412.         }
  413.         $dt->mult(-1);
  414.         $this->add($dt);
  415.     }
  416.  
  417.     /**
  418.      * to know the duration between two dates.
  419.      * @param jDateTime $dt  the date on which a sub will be made with the date on the current object
  420.      * @param bool $absolute 
  421.      * @return jDuration a jDuration object
  422.      */
  423.     public function durationTo($dt$absolute=true){
  424.         if($absolute){
  425.             $t gmmktime($dt->hour$dt->minute$dt->second,
  426.                 $dt->month$dt->day$dt->year)
  427.                 - gmmktime($this->hour$this->minute$this->second,
  428.                     $this->month$this->day$this->year);
  429.             return new jDuration($t);
  430.         }
  431.         else{
  432.             return new jDuration(array(
  433.                 "year" => $dt->year $this->year,
  434.                 "month" => $dt->month $this->month,
  435.                 "day" => $dt->day $this-> day,
  436.                 "hour" => $dt->hour $this->hour,
  437.                 "minute" => $dt->minute $this->minute,
  438.                 "second" => $dt->second $this->second
  439.             ));
  440.         }
  441.     }
  442.  
  443.     /**
  444.      * compare two date
  445.      * @param jDateTime $dt the date to compare
  446.      * @return integer -1 if $dt > $this, 0 if $dt = $this, 1 if $dt < $this
  447.      */
  448.     public function compareTo($dt){
  449.         $fields=array('year','month','day','hour','minute','second');
  450.         foreach($fields as $field){
  451.             if($dt->$field $this->$field)
  452.                 return -1;
  453.             if($dt->$field $this->$field)
  454.                 return 1;
  455.         }
  456.         return 0;
  457.     }
  458.  
  459.     /**
  460.     * set date to current datetime
  461.     */
  462.     public function now({
  463.         $this->year = intval(date('Y'));
  464.         $this->month = intval(date('m'));
  465.         $this->day = intval(date('d'));
  466.         $this->hour = intval(date('H'));
  467.         $this->minute = intval(date('i'));
  468.         $this->second = intval(date('s'));
  469.     }
  470.  
  471.  
  472.     /**
  473.     * Substract a date with another
  474.     * @param jDateTime $date 
  475.     * @return jDateTime 
  476.     * @author Hadrien Lanneau <hadrien@over-blog.com>
  477.     * @since 1.2
  478.     */
  479.     public function substract($date null{
  480.         if (!$date{
  481.             $date new jDateTime();
  482.             $date->now();
  483.         }
  484.  
  485.         $newDate new jDateTime();
  486.  
  487.         $items array(
  488.                 'second',
  489.                 'minute',
  490.                 'hour',
  491.                 'day',
  492.                 'month',
  493.                 'year'
  494.             );
  495.  
  496.         foreach ($items as $k => $i{
  497.             $newDate->{$i$date->{$i$this->{$i};
  498.             if ($newDate->{$i0{
  499.                 switch ($i{
  500.                     case 'second':
  501.                     case 'minute':
  502.                         $sub 60;
  503.                         break;
  504.                     case 'hour':
  505.                         $sub 24;
  506.                         break;
  507.                     case 'day':
  508.                         switch ($this->month{
  509.                             // Month with 31 days
  510.                             case 1:
  511.                             case 3:
  512.                             case 5:
  513.                             case 7:
  514.                             case 8:
  515.                             case 10:
  516.                             case 12:
  517.                                 $sub 31;
  518.                                 break;
  519.                             // Month with 30 days
  520.                             case 4:
  521.                             case 6:
  522.                             case 9:
  523.                             case 11:
  524.                                 $sub 30;
  525.                                 break;
  526.                             // February
  527.                             case 2:
  528.                                 if ($this->year == and
  529.                                         !(
  530.                                                 $this->year 100 == and
  531.                                                 $this->year 400 != 0
  532.                                         )) {
  533.                                     // Bissextile
  534.                                     $sub 29;
  535.                                 }
  536.                                 else {
  537.                                    $sub 28;
  538.                                 }
  539.                                 break;
  540.                         }
  541.                         break;
  542.                     case 'month':
  543.                         $sub 12;
  544.                         break;
  545.                     default:
  546.                         $sub 0;
  547.                 }
  548.                 $newDate->{$iabs($sub $newDate->{$i});
  549.                 if (isset($items[$k+1])) {
  550.                     $newDate->{$items[$k+1]}--;
  551.                 }
  552.             }
  553.         }
  554.         return $newDate;
  555.     }
  556. }

Documentation generated on Thu, 19 Sep 2013 00:03:51 +0200 by phpDocumentor 1.4.3