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[$key] = intval($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 > 0 && $this->month > 0 && $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 === 0 && $this->month === 0 && $this->day === 0 && $this->hour == 0 && $this->minute == 0 && $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 , 0, 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<2) break;
  292.                     $this->month = intval($match[2]);
  293.                     if($c<3) break;
  294.                     $this->day = intval($match[3]);
  295.                     if($c<4) break;
  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_months) + 1;
  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->{$i} < 0) {
  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 % 4 == 0 and
  529.                                         !(
  530.                                                 $this->year % 100 == 0 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->{$i} = abs($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