Subversion-Projekte lars-tiefland.prado

Revision

Blame | Letzte Änderung | Log anzeigen | RSS feed

<?php
/**
 * TSimpleDateFormatter class file
 *
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 * @link http://www.pradosoft.com/
 * @copyright Copyright &copy; 2005-2008 PradoSoft
 * @license http://www.pradosoft.com/license/
 * @version $Id: TSimpleDateFormatter.php 2488 2008-08-06 01:34:06Z knut $
 * @package System.Util
 */

/**
 * TSimpleDateFormatter class.
 *
 * Formats and parses dates using the SimpleDateFormat pattern.
 * This pattern is compatible with the I18N and java's SimpleDateFormatter.
 * <code>
 * Pattern |      Description
 * ----------------------------------------------------
 * d       | Day of month 1 to 31, no padding
 * dd      | Day of monath 01 to 31, zero leading
 * M       | Month digit 1 to 12, no padding
 * MM      | Month digit 01 to 12, zero leading
 * yy      | 2 year digit, e.g., 96, 05
 * yyyy    | 4 year digit, e.g., 2005
 * ----------------------------------------------------
 * </code>
 *
 * Usage example, to format a date
 * <code>
 * $formatter = new TSimpleDateFormatter("dd/MM/yyy");
 * echo $formatter->format(time());
 * </code>
 *
 * To parse the date string into a date timestamp.
 * <code>
 * $formatter = new TSimpleDateFormatter("d-M-yyy");
 * echo $formatter->parse("24-6-2005");
 * </code>
 *
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 * @version $Id: TSimpleDateFormatter.php 2488 2008-08-06 01:34:06Z knut $
 * @package System.Util
 * @since 3.0
 */
class TSimpleDateFormatter
{
        /**
         * Formatting pattern.
         * @var string
         */
        private $pattern;

        /**
         * Charset, default is 'UTF-8'
         * @var string
         */
        private $charset = 'UTF-8';

        /**
         * Constructor, create a new date time formatter.
         * @param string formatting pattern.
         * @param string pattern and value charset
         */
        public function __construct($pattern, $charset='UTF-8')
        {
                $this->setPattern($pattern);
                $this->setCharset($charset);
        }

        /**
         * @return string formatting pattern.
         */
        public function getPattern()
        {
                return $this->pattern;
        }

        /**
         * @param string formatting pattern.
         */
        public function setPattern($pattern)
        {
                $this->pattern = $pattern;
        }

        /**
         * @return string formatting charset.
         */
        public function getCharset()
        {
                return $this->charset;
        }

        /**
         * @param string formatting charset.
         */
        public function setCharset($charset)
        {
                $this->charset = $charset;
        }

        /**
         * Format the date according to the pattern.
         * @param string|int the date to format, either integer or a string readable by strtotime.
         * @return string formatted date.
         */
        public function format($value)
        {
                $date = $this->getDate($value);
                $bits['yyyy'] = $date['year'];
                $bits['yy'] = substr("{$date['year']}", -2);

                $bits['MM'] = str_pad("{$date['mon']}", 2, '0', STR_PAD_LEFT);
                $bits['M'] = $date['mon'];

                $bits['dd'] = str_pad("{$date['mday']}", 2, '0', STR_PAD_LEFT);
                $bits['d'] = $date['mday'];

                $pattern = preg_replace('/M{3,4}/', 'MM', $this->pattern);
                return str_replace(array_keys($bits), $bits, $pattern);
        }

        public function getMonthPattern()
        {
                if(is_int(strpos($this->pattern, 'MMMM')))
                        return 'MMMM';
                if(is_int(strpos($this->pattern, 'MMM')))
                        return 'MMM';
                if(is_int(strpos($this->pattern, 'MM')))
                        return 'MM';
                if(is_int(strpos($this->pattern, 'M')))
                        return 'M';
                return false;
        }

        public function getDayPattern()
        {
                if(is_int(strpos($this->pattern, 'dd')))
                        return 'dd';
                if(is_int(strpos($this->pattern, 'd')))
                        return 'd';
                return false;
        }

        public function getYearPattern()
        {
                if(is_int(strpos($this->pattern, 'yyyy')))
                        return 'yyyy';
                if(is_int(strpos($this->pattern, 'yy')))
                        return 'yy';
                return false;
        }

        public function getDayMonthYearOrdering()
        {
                $ordering = array();
                if(is_int($day= strpos($this->pattern, 'd')))
                        $ordering['day'] = $day;
                if(is_int($month= strpos($this->pattern, 'M')))
                        $ordering['month'] = $month;
                if(is_int($year= strpos($this->pattern, 'yy')))
                        $ordering['year'] = $year;
                asort($ordering);
                return array_keys($ordering);
        }

        /**
         * Gets the time stamp from string or integer.
         * @param string|int date to parse
         * @return array date info array
         */
        private function getDate($value)
        {
                if(!is_string($value))
                {
                        $s = Prado::createComponent('System.Util.TDateTimeStamp');
                        return $s->getDate($value);
                }
                $date = @strtotime($value);
                if($date < 0)
                        throw new TInvalidDataValueException('invalid_date', $value);
                return @getdate($date);
        }

        /**
         * @return boolean true if the given value matches with the date pattern.
         */
        public function isValidDate($value)
        {
                if($value === null) {
                        return false;
                } else {
                        return $this->parse($value, false) !== null;
                }
        }

        /**
         * Parse the string according to the pattern.
         * @param string|int date string or integer to parse
         * @return int date time stamp
         * @throws TInvalidDataValueException if date string is malformed.
         */
        public function parse($value,$defaultToCurrentTime=true)
        {
                if(is_int($value) || is_float($value))
                        return $value;
                else if(!is_string($value))
                        throw new TInvalidDataValueException('date_to_parse_must_be_string', $value);

                if(empty($this->pattern)) return time();

                $date = time();

                if($this->length(trim($value)) < 1)
                        return $defaultToCurrentTime ? $date : null;

                $pattern = $this->pattern;

                $i_val = 0;
                $i_format = 0;
                $pattern_length = $this->length($pattern);
                $c = '';
                $token='';
                $x=null; $y=null;


                if($defaultToCurrentTime)
                {
                        $year = "{$date['year']}";
                        $month = $date['mon'];
                        $day = $date['mday'];
                }
                else
                {
                        $year = null;
                        $month = null;
                        $day = null;
                }

                while ($i_format < $pattern_length)
                {
                        $c = $this->charAt($pattern,$i_format);
                        $token='';
                        while ($this->charEqual($pattern, $i_format, $c)
                                                && ($i_format < $pattern_length))
                        {
                                $token .= $this->charAt($pattern, $i_format++);
                        }

                        if ($token=='yyyy' || $token=='yy' || $token=='y')
                        {
                                if ($token=='yyyy') { $x=4;$y=4; }
                                if ($token=='yy')   { $x=2;$y=2; }
                                if ($token=='y')    { $x=2;$y=4; }
                                $year = $this->getInteger($value,$i_val,$x,$y);
                                if($year === null)
                                        return null;
                                        //throw new TInvalidDataValueException('Invalid year', $value);
                                $i_val += strlen($year);
                                if(strlen($year) == 2)
                                {
                                        $iYear = (int)$year;
                                        if($iYear > 70)
                                                $year = $iYear + 1900;
                                        else
                                                $year = $iYear + 2000;
                                }
                                $year = (int)$year;
                        }
                        elseif($token=='MM' || $token=='M')
                        {
                                $month=$this->getInteger($value,$i_val,
                                                                        $this->length($token),2);
                                $iMonth = (int)$month;
                                if($month === null || $iMonth < 1 || $iMonth > 12 )
                                        return null;
                                        //throw new TInvalidDataValueException('Invalid month', $value);
                                $i_val += strlen($month);
                                $month = $iMonth;
                        }
                        elseif ($token=='dd' || $token=='d')
                        {
                                $day = $this->getInteger($value,$i_val,
                                                                        $this->length($token), 2);
                                $iDay = (int)$day;
                                if($day === null || $iDay < 1 || $iDay >31)
                                        return null;
                                        //throw new TInvalidDataValueException('Invalid day', $value);
                                $i_val += strlen($day);
                                $day = $iDay;
                        }
                        else
                        {
                                if($this->substring($value, $i_val, $this->length($token)) != $token)
                                        return null;
                                        //throw new TInvalidDataValueException("Subpattern '{$this->pattern}' mismatch", $value);
                                else
                                        $i_val += $this->length($token);
                        }
                }
                if ($i_val != $this->length($value))
                        throw new TInvalidDataValueException("Pattern '{$this->pattern}' mismatch", $value);
                if(!$defaultToCurrentTime && ($month === null || $day === null || $year === null))
                        return null;
                else
                {               
                        if(empty($year)) {
                                $year = date('Y');
                        }
                        $day = (int)$day <= 0 ? 1 : (int)$day;
                        $month = (int)$month <= 0 ? 1 : (int)$month;
                        $s = Prado::createComponent('System.Util.TDateTimeStamp');
                        return $s->getTimeStamp(0, 0, 0, $month, $day, $year);
                }
        }

        /**
         * Calculate the length of a string, may be consider iconv_strlen?
         */
        private function length($string)
        {
                //use iconv_strlen or just strlen?
                return strlen($string);
        }

        /**
         * Get the char at a position.
         */
        private function charAt($string, $pos)
        {
                return $this->substring($string, $pos, 1);
        }

        /**
         * Gets a portion of a string, uses iconv_substr.
         */
        private function substring($string, $start, $length)
        {
                return iconv_substr($string, $start, $length);
        }

        /**
         * Returns true if char at position equals a particular char.
         */
        private function charEqual($string, $pos, $char)
        {
                return $this->charAt($string, $pos) == $char;
        }

        /**
         * Gets integer from part of a string, allows integers of any length.
         * @param string string to retrieve the integer from.
         * @param int starting position
         * @param int minimum integer length
         * @param int maximum integer length
         * @return string integer portion of the string, null otherwise
         */
        private function getInteger($str,$i,$minlength,$maxlength)
        {
                //match for digits backwards
                for ($x = $maxlength; $x >= $minlength; $x--)
                {
                        $token= $this->substring($str, $i,$x);
                        if ($this->length($token) < $minlength)
                                return null;
                        if (preg_match('/^\d+$/', $token))
                                return $token;
                }
                return null;
        }
}

?>