File indexing completed on 2024-12-22 05:36:50

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Locale
0017  * @subpackage Format
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @version    $Id$
0020  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0021  */
0022 
0023 /**
0024  * include needed classes
0025  */
0026 // require_once 'Zend/Locale/Data.php';
0027 
0028 /**
0029  * @category   Zend
0030  * @package    Zend_Locale
0031  * @subpackage Format
0032  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0033  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0034  */
0035 class Zend_Locale_Format
0036 {
0037     const STANDARD   = 'auto';
0038 
0039     private static $_options = array('date_format'   => null,
0040                                      'number_format' => null,
0041                                      'format_type'   => 'iso',
0042                                      'fix_date'      => false,
0043                                      'locale'        => null,
0044                                      'cache'         => null,
0045                                      'disableCache'  => null,
0046                                      'precision'     => null);
0047 
0048     /**
0049      * Sets class wide options, if no option was given, the actual set options will be returned
0050      * The 'precision' option of a value is used to truncate or stretch extra digits. -1 means not to touch the extra digits.
0051      * The 'locale' option helps when parsing numbers and dates using separators and month names.
0052      * The date format 'format_type' option selects between CLDR/ISO date format specifier tokens and PHP's date() tokens.
0053      * The 'fix_date' option enables or disables heuristics that attempt to correct invalid dates.
0054      * The 'number_format' option can be used to specify a default number format string
0055      * The 'date_format' option can be used to specify a default date format string, but beware of using getDate(),
0056      * checkDateFormat() and getTime() after using setOptions() with a 'format'.  To use these four methods
0057      * with the default date format for a locale, use array('date_format' => null, 'locale' => $locale) for their options.
0058      *
0059      * @param  array  $options  Array of options, keyed by option name: format_type = 'iso' | 'php', fix_date = true | false,
0060      *                          locale = Zend_Locale | locale string, precision = whole number between -1 and 30
0061      * @throws Zend_Locale_Exception
0062      * @return array if no option was given
0063      */
0064     public static function setOptions(array $options = array())
0065     {
0066         self::$_options = self::_checkOptions($options) + self::$_options;
0067         return self::$_options;
0068     }
0069 
0070     /**
0071      * Internal function for checking the options array of proper input values
0072      * See {@link setOptions()} for details.
0073      *
0074      * @param  array  $options  Array of options, keyed by option name: format_type = 'iso' | 'php', fix_date = true | false,
0075      *                          locale = Zend_Locale | locale string, precision = whole number between -1 and 30
0076      * @throws Zend_Locale_Exception
0077      * @return array if no option was given
0078      */
0079     private static function _checkOptions(array $options = array())
0080     {
0081         if (count($options) == 0) {
0082             return self::$_options;
0083         }
0084         foreach ($options as $name => $value) {
0085             $name  = strtolower($name);
0086             if ($name !== 'locale') {
0087                 if (gettype($value) === 'string') {
0088                     $value = strtolower($value);
0089                 }
0090             }
0091 
0092             switch($name) {
0093                 case 'number_format' :
0094                     if ($value == Zend_Locale_Format::STANDARD) {
0095                         $locale = self::$_options['locale'];
0096                         if (isset($options['locale'])) {
0097                             $locale = $options['locale'];
0098                         }
0099                         $options['number_format'] = Zend_Locale_Data::getContent($locale, 'decimalnumber');
0100                     } else if ((gettype($value) !== 'string') and ($value !== NULL)) {
0101                         // require_once 'Zend/Locale/Exception.php';
0102                         $stringValue = (string)(is_array($value) ? implode(' ', $value) : $value);
0103                         throw new Zend_Locale_Exception("Unknown number format type '" . gettype($value) . "'. "
0104                             . "Format '$stringValue' must be a valid number format string.");
0105                     }
0106                     break;
0107 
0108                 case 'date_format' :
0109                     if ($value == Zend_Locale_Format::STANDARD) {
0110                         $locale = self::$_options['locale'];
0111                         if (isset($options['locale'])) {
0112                             $locale = $options['locale'];
0113                         }
0114                         $options['date_format'] = Zend_Locale_Format::getDateFormat($locale);
0115                     } else if ((gettype($value) !== 'string') and ($value !== NULL)) {
0116                         // require_once 'Zend/Locale/Exception.php';
0117                         $stringValue = (string)(is_array($value) ? implode(' ', $value) : $value);
0118                         throw new Zend_Locale_Exception("Unknown dateformat type '" . gettype($value) . "'. "
0119                             . "Format '$stringValue' must be a valid ISO or PHP date format string.");
0120                     } else {
0121                         if (((isset($options['format_type']) === true) and ($options['format_type'] == 'php')) or
0122                             ((isset($options['format_type']) === false) and (self::$_options['format_type'] == 'php'))) {
0123                             $options['date_format'] = Zend_Locale_Format::convertPhpToIsoFormat($value);
0124                         }
0125                     }
0126                     break;
0127 
0128                 case 'format_type' :
0129                     if (($value != 'php') && ($value != 'iso')) {
0130                         // require_once 'Zend/Locale/Exception.php';
0131                         throw new Zend_Locale_Exception("Unknown date format type '$value'. Only 'iso' and 'php'"
0132                            . " are supported.");
0133                     }
0134                     break;
0135 
0136                 case 'fix_date' :
0137                     if (($value !== true) && ($value !== false)) {
0138                         // require_once 'Zend/Locale/Exception.php';
0139                         throw new Zend_Locale_Exception("Enabling correction of dates must be either true or false"
0140                             . "(fix_date='$value').");
0141                     }
0142                     break;
0143 
0144                 case 'locale' :
0145                     $options['locale'] = Zend_Locale::findLocale($value);
0146                     break;
0147 
0148                 case 'cache' :
0149                     if ($value instanceof Zend_Cache_Core) {
0150                         Zend_Locale_Data::setCache($value);
0151                     }
0152                     break;
0153 
0154                 case 'disablecache' :
0155                     if (null !== $value) {
0156                         Zend_Locale_Data::disableCache($value);
0157                     }
0158                     break;
0159 
0160                 case 'precision' :
0161                     if ($value === NULL) {
0162                         $value = -1;
0163                     }
0164 
0165                     if (($value < -1) || ($value > 30)) {
0166                         // require_once 'Zend/Locale/Exception.php';
0167                         throw new Zend_Locale_Exception("'$value' precision is not a whole number less than 30.");
0168                     }
0169                     break;
0170 
0171                 default:
0172                     // require_once 'Zend/Locale/Exception.php';
0173                     throw new Zend_Locale_Exception("Unknown option: '$name' = '$value'");
0174                     break;
0175 
0176             }
0177         }
0178 
0179         return $options;
0180     }
0181 
0182     /**
0183      * Changes the numbers/digits within a given string from one script to another
0184      * 'Decimal' representated the stardard numbers 0-9, if a script does not exist
0185      * an exception will be thrown.
0186      *
0187      * Examples for conversion from Arabic to Latin numerals:
0188      *   convertNumerals('١١٠ Tests', 'Arab'); -> returns '100 Tests'
0189      * Example for conversion from Latin to Arabic numerals:
0190      *   convertNumerals('100 Tests', 'Latn', 'Arab'); -> returns '١١٠ Tests'
0191      *
0192      * @param  string  $input  String to convert
0193      * @param  string  $from   Script to parse, see {@link Zend_Locale::getScriptList()} for details.
0194      * @param  string  $to     OPTIONAL Script to convert to
0195      * @return string  Returns the converted input
0196      * @throws Zend_Locale_Exception
0197      */
0198     public static function convertNumerals($input, $from, $to = null)
0199     {
0200         if (!self::_getUniCodeSupport()) {
0201             trigger_error("Sorry, your PCRE extension does not support UTF8 which is needed for the I18N core", E_USER_NOTICE);
0202         }
0203 
0204         $from   = strtolower($from);
0205         $source = Zend_Locale_Data::getContent('en', 'numberingsystem', $from);
0206         if (empty($source)) {
0207             // require_once 'Zend/Locale/Exception.php';
0208             throw new Zend_Locale_Exception("Unknown script '$from'. Use 'Latn' for digits 0,1,2,3,4,5,6,7,8,9.");
0209         }
0210 
0211         if ($to !== null) {
0212             $to     = strtolower($to);
0213             $target = Zend_Locale_Data::getContent('en', 'numberingsystem', $to);
0214             if (empty($target)) {
0215                 // require_once 'Zend/Locale/Exception.php';
0216                 throw new Zend_Locale_Exception("Unknown script '$to'. Use 'Latn' for digits 0,1,2,3,4,5,6,7,8,9.");
0217             }
0218         } else {
0219             $target = '0123456789';
0220         }
0221 
0222         for ($x = 0; $x < 10; ++$x) {
0223             $asource[$x] = "/" . iconv_substr($source, $x, 1, 'UTF-8') . "/u";
0224             $atarget[$x] = iconv_substr($target, $x, 1, 'UTF-8');
0225         }
0226 
0227         return preg_replace($asource, $atarget, $input);
0228     }
0229 
0230     /**
0231      * Returns the normalized number from a localized one
0232      * Parsing depends on given locale (grouping and decimal)
0233      *
0234      * Examples for input:
0235      * '2345.4356,1234' = 23455456.1234
0236      * '+23,3452.123' = 233452.123
0237      * '12343 ' = 12343
0238      * '-9456' = -9456
0239      * '0' = 0
0240      *
0241      * @param  string $input    Input string to parse for numbers
0242      * @param  array  $options  Options: locale, precision. See {@link setOptions()} for details.
0243      * @return string Returns the extracted number
0244      * @throws Zend_Locale_Exception
0245      */
0246     public static function getNumber($input, array $options = array())
0247     {
0248         $options = self::_checkOptions($options) + self::$_options;
0249         if (!is_string($input)) {
0250             return $input;
0251         }
0252 
0253         if (!self::isNumber($input, $options)) {
0254             // require_once 'Zend/Locale/Exception.php';
0255             throw new Zend_Locale_Exception('No localized value in ' . $input . ' found, or the given number does not match the localized format');
0256         }
0257 
0258         // Get correct signs for this locale
0259         $symbols = Zend_Locale_Data::getList($options['locale'],'symbols');
0260         // Change locale input to be default number
0261         if (($input[0] == $symbols['minus']) && ('-' != $input[0])) {
0262             $input = '-' . substr($input, 1);
0263         }
0264 
0265         $input = str_replace($symbols['group'],'', $input);
0266         if (strpos($input, $symbols['decimal']) !== false) {
0267             if ($symbols['decimal'] != '.') {
0268                 $input = str_replace($symbols['decimal'], ".", $input);
0269             }
0270 
0271             $pre = substr($input, strpos($input, '.') + 1);
0272             if ($options['precision'] === null) {
0273                 $options['precision'] = strlen($pre);
0274             }
0275 
0276             if (strlen($pre) >= $options['precision']) {
0277                 $input = substr($input, 0, strlen($input) - strlen($pre) + $options['precision']);
0278             }
0279 
0280             if (($options['precision'] == 0) && ($input[strlen($input) - 1] == '.')) {
0281                 $input = substr($input, 0, -1);
0282             }
0283         }
0284 
0285         return $input;
0286     }
0287 
0288     /**
0289      * Returns a locale formatted number depending on the given options.
0290      * The seperation and fraction sign is used from the set locale.
0291      * ##0.#  -> 12345.12345 -> 12345.12345
0292      * ##0.00 -> 12345.12345 -> 12345.12
0293      * ##,##0.00 -> 12345.12345 -> 12,345.12
0294      *
0295      * @param   string  $value    Localized number string
0296      * @param   array   $options  Options: number_format, locale, precision. See {@link setOptions()} for details.
0297      * @return  string  locale formatted number
0298      * @throws Zend_Locale_Exception
0299      */
0300     public static function toNumber($value, array $options = array())
0301     {
0302         // load class within method for speed
0303         // require_once 'Zend/Locale/Math.php';
0304 
0305         $value             = Zend_Locale_Math::floatalize($value);
0306         $value             = Zend_Locale_Math::normalize($value);
0307         $options           = self::_checkOptions($options) + self::$_options;
0308         $options['locale'] = (string) $options['locale'];
0309 
0310         // Get correct signs for this locale
0311         $symbols = Zend_Locale_Data::getList($options['locale'], 'symbols');
0312         $oenc = self::_getEncoding();
0313         self::_setEncoding('UTF-8');
0314         
0315         // Get format
0316         $format = $options['number_format'];
0317         if ($format === null) {
0318             $format  = Zend_Locale_Data::getContent($options['locale'], 'decimalnumber');
0319             $format  = self::_seperateFormat($format, $value, $options['precision']);
0320 
0321             if ($options['precision'] !== null) {
0322                 $value   = Zend_Locale_Math::normalize(Zend_Locale_Math::round($value, $options['precision']));
0323             }
0324         } else {
0325             // seperate negative format pattern when available
0326             $format  = self::_seperateFormat($format, $value, $options['precision']);
0327             if (strpos($format, '.')) {
0328                 if (is_numeric($options['precision'])) {
0329                     $value = Zend_Locale_Math::round($value, $options['precision']);
0330                 } else {
0331                     if (substr($format, iconv_strpos($format, '.') + 1, 3) == '###') {
0332                         $options['precision'] = null;
0333                     } else {
0334                         $options['precision'] = iconv_strlen(iconv_substr($format, iconv_strpos($format, '.') + 1,
0335                                                              iconv_strrpos($format, '0') - iconv_strpos($format, '.')));
0336                         $format = iconv_substr($format, 0, iconv_strpos($format, '.') + 1) . '###'
0337                                 . iconv_substr($format, iconv_strrpos($format, '0') + 1);
0338                     }
0339                 }
0340             } else {
0341                 $value = Zend_Locale_Math::round($value, 0);
0342                 $options['precision'] = 0;
0343             }
0344             $value = Zend_Locale_Math::normalize($value);
0345         }
0346 
0347         if (iconv_strpos($format, '0') === false) {
0348             self::_setEncoding($oenc);
0349             // require_once 'Zend/Locale/Exception.php';
0350             throw new Zend_Locale_Exception('Wrong format... missing 0');
0351         }
0352 
0353         // get number parts
0354         $pos = iconv_strpos($value, '.');
0355         if ($pos !== false) {
0356             if ($options['precision'] === null) {
0357                 $precstr = iconv_substr($value, $pos + 1);
0358             } else {
0359                 $precstr = iconv_substr($value, $pos + 1, $options['precision']);
0360                 if (iconv_strlen($precstr) < $options['precision']) {
0361                     $precstr = $precstr . str_pad("0", ($options['precision'] - iconv_strlen($precstr)), "0");
0362                 }
0363             }
0364         } else {
0365             if ($options['precision'] > 0) {
0366                 $precstr = str_pad("0", ($options['precision']), "0");
0367             }
0368         }
0369 
0370         if ($options['precision'] === null) {
0371             if (isset($precstr)) {
0372                 $options['precision'] = iconv_strlen($precstr);
0373             } else {
0374                 $options['precision'] = 0;
0375             }
0376         }
0377 
0378         // get fraction and format lengths
0379         if (strpos($value, '.') !== false) {
0380             $number = substr((string) $value, 0, strpos($value, '.'));
0381         } else {
0382             $number = $value;
0383         }
0384 
0385         $prec = call_user_func(Zend_Locale_Math::$sub, $value, $number, $options['precision']);
0386         $prec = Zend_Locale_Math::floatalize($prec);
0387         $prec = Zend_Locale_Math::normalize($prec);
0388         if (iconv_strpos($prec, '-') !== false) {
0389             $prec = iconv_substr($prec, 1);
0390         }
0391 
0392         if (($prec == 0) and ($options['precision'] > 0)) {
0393             $prec = "0.0";
0394         }
0395 
0396         if (($options['precision'] + 2) > iconv_strlen($prec)) {
0397             $prec = str_pad((string) $prec, $options['precision'] + 2, "0", STR_PAD_RIGHT);
0398         }
0399 
0400         if (iconv_strpos($number, '-') !== false) {
0401             $number = iconv_substr($number, 1);
0402         }
0403         $group  = iconv_strrpos($format, ',');
0404         $group2 = iconv_strpos ($format, ',');
0405         $point  = iconv_strpos ($format, '0');
0406         // Add fraction
0407         $rest = "";
0408         if (iconv_strpos($format, '.')) {
0409             $rest   = iconv_substr($format, iconv_strpos($format, '.') + 1);
0410             $length = iconv_strlen($rest);
0411             for($x = 0; $x < $length; ++$x) {
0412                 if (($rest[0] == '0') || ($rest[0] == '#')) {
0413                     $rest = iconv_substr($rest, 1);
0414                 }
0415             }
0416             $format = iconv_substr($format, 0, iconv_strlen($format) - iconv_strlen($rest));
0417         }
0418 
0419         if ($options['precision'] == '0') {
0420             if (iconv_strrpos($format, '-') != 0) {
0421                 $format = iconv_substr($format, 0, $point)
0422                         . iconv_substr($format, iconv_strrpos($format, '#') + 2);
0423             } else {
0424                 $format = iconv_substr($format, 0, $point);
0425             }
0426         } else {
0427             $format = iconv_substr($format, 0, $point) . $symbols['decimal']
0428                                . iconv_substr($prec, 2);
0429         }
0430 
0431         $format .= $rest;
0432         // Add seperation
0433         if ($group == 0) {
0434             // no seperation
0435             $format = $number . iconv_substr($format, $point);
0436         } else if ($group == $group2) {
0437             // only 1 seperation
0438             $seperation = ($point - $group);
0439             for ($x = iconv_strlen($number); $x > $seperation; $x -= $seperation) {
0440                 if (iconv_substr($number, 0, $x - $seperation) !== "") {
0441                     $number = iconv_substr($number, 0, $x - $seperation) . $symbols['group']
0442                             . iconv_substr($number, $x - $seperation);
0443                 }
0444             }
0445             $format = iconv_substr($format, 0, iconv_strpos($format, '#')) . $number . iconv_substr($format, $point);
0446         } else {
0447 
0448             // 2 seperations
0449             if (iconv_strlen($number) > ($point - $group)) {
0450                 $seperation = ($point - $group);
0451                 $number = iconv_substr($number, 0, iconv_strlen($number) - $seperation) . $symbols['group']
0452                         . iconv_substr($number, iconv_strlen($number) - $seperation);
0453 
0454                 if ((iconv_strlen($number) - 1) > ($point - $group + 1)) {
0455                     $seperation2 = ($group - $group2 - 1);
0456                     for ($x = iconv_strlen($number) - $seperation2 - 2; $x > $seperation2; $x -= $seperation2) {
0457                         $number = iconv_substr($number, 0, $x - $seperation2) . $symbols['group']
0458                                 . iconv_substr($number, $x - $seperation2);
0459                     }
0460                 }
0461 
0462             }
0463             $format = iconv_substr($format, 0, iconv_strpos($format, '#')) . $number . iconv_substr($format, $point);
0464         }
0465         // set negative sign
0466         if (call_user_func(Zend_Locale_Math::$comp, $value, 0, $options['precision']) < 0) {
0467             if (iconv_strpos($format, '-') === false) {
0468                 $format = $symbols['minus'] . $format;
0469             } else {
0470                 $format = str_replace('-', $symbols['minus'], $format);
0471             }
0472         }
0473 
0474         self::_setEncoding($oenc);
0475         return (string) $format;
0476     }
0477 
0478     /**
0479      * @param string $format
0480      * @param string $value
0481      * @param int $precision
0482      * @return string
0483      */
0484     private static function _seperateFormat($format, $value, $precision)
0485     {
0486         if (iconv_strpos($format, ';') !== false) {
0487             if (call_user_func(Zend_Locale_Math::$comp, $value, 0, $precision) < 0) {
0488                 $tmpformat = iconv_substr($format, iconv_strpos($format, ';') + 1);
0489                 if ($tmpformat[0] == '(') {
0490                     $format = iconv_substr($format, 0, iconv_strpos($format, ';'));
0491                 } else {
0492                     $format = $tmpformat;
0493                 }
0494             } else {
0495                 $format = iconv_substr($format, 0, iconv_strpos($format, ';'));
0496             }
0497         }
0498 
0499         return $format;
0500     }
0501 
0502 
0503     /**
0504      * Checks if the input contains a normalized or localized number
0505      *
0506      * @param   string  $input    Localized number string
0507      * @param   array   $options  Options: locale. See {@link setOptions()} for details.
0508      * @return  boolean           Returns true if a number was found
0509      */
0510     public static function isNumber($input, array $options = array())
0511     {
0512         if (!self::_getUniCodeSupport()) {
0513             trigger_error("Sorry, your PCRE extension does not support UTF8 which is needed for the I18N core", E_USER_NOTICE);
0514         }
0515 
0516         $options = self::_checkOptions($options) + self::$_options;
0517 
0518         // Get correct signs for this locale
0519         $symbols = Zend_Locale_Data::getList($options['locale'],'symbols');
0520 
0521         $regexs = Zend_Locale_Format::_getRegexForType('decimalnumber', $options);
0522         $regexs = array_merge($regexs, Zend_Locale_Format::_getRegexForType('scientificnumber', $options));
0523         if (!empty($input) && ($input[0] == $symbols['decimal'])) {
0524             $input = 0 . $input;
0525         }
0526         foreach ($regexs as $regex) {
0527             preg_match($regex, $input, $found);
0528             if (isset($found[0])) {
0529                 return true;
0530             }
0531         }
0532 
0533         return false;
0534     }
0535 
0536     /**
0537      * Internal method to convert cldr number syntax into regex
0538      *
0539      * @param  string $type
0540      * @param  array  $options Options: locale. See {@link setOptions()} for details.
0541      * @return string
0542      * @throws Zend_Locale_Exception
0543      */
0544     private static function _getRegexForType($type, $options)
0545     {
0546         $decimal  = Zend_Locale_Data::getContent($options['locale'], $type);
0547         $decimal  = preg_replace('/[^#0,;\.\-Ee]/u', '',$decimal);
0548         $patterns = explode(';', $decimal);
0549 
0550         if (count($patterns) == 1) {
0551             $patterns[1] = '-' . $patterns[0];
0552         }
0553 
0554         $symbols = Zend_Locale_Data::getList($options['locale'],'symbols');
0555 
0556         foreach($patterns as $pkey => $pattern) {
0557             $regex[$pkey]  = '/^';
0558             $rest   = 0;
0559             $end    = null;
0560             if (strpos($pattern, '.') !== false) {
0561                 $end     = substr($pattern, strpos($pattern, '.') + 1);
0562                 $pattern = substr($pattern, 0, -strlen($end) - 1);
0563             }
0564 
0565             if (strpos($pattern, ',') !== false) {
0566                 $parts = explode(',', $pattern);
0567                 $count = count($parts);
0568                 foreach($parts as $key => $part) {
0569                     switch ($part) {
0570                         case '#':
0571                         case '-#':
0572                             if ($part[0] == '-') {
0573                                 $regex[$pkey] .= '[' . $symbols['minus'] . '-]{0,1}';
0574                             } else {
0575                                 $regex[$pkey] .= '[' . $symbols['plus'] . '+]{0,1}';
0576                             }
0577 
0578                             if (($parts[$key + 1]) == '##0')  {
0579                                 $regex[$pkey] .= '[0-9]{1,3}';
0580                             } else if (($parts[$key + 1]) == '##') {
0581                                 $regex[$pkey] .= '[0-9]{1,2}';
0582                             } else {
0583                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 1):"' . $pattern . '"');
0584                             }
0585                             break;
0586                         case '##':
0587                             if ($parts[$key + 1] == '##0') {
0588                                 $regex[$pkey] .=  '(\\' . $symbols['group'] . '{0,1}[0-9]{2})*';
0589                             } else {
0590                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 2):"' . $pattern . '"');
0591                             }
0592                             break;
0593                         case '##0':
0594                             if ($parts[$key - 1] == '##') {
0595                                 $regex[$pkey] .= '[0-9]';
0596                             } else if (($parts[$key - 1] == '#') || ($parts[$key - 1] == '-#')) {
0597                                 $regex[$pkey] .= '(\\' . $symbols['group'] . '{0,1}[0-9]{3})*';
0598                             } else {
0599                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 3):"' . $pattern . '"');
0600                             }
0601                             break;
0602                         case '#0':
0603                             if ($key == 0) {
0604                                 $regex[$pkey] .= '[0-9]*';
0605                             } else {
0606                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 4):"' . $pattern . '"');
0607                             }
0608                             break;
0609                     }
0610                 }
0611             }
0612 
0613             if (strpos($pattern, 'E') !== false) {
0614                 if (($pattern == '#E0') || ($pattern == '#E00')) {
0615                     $regex[$pkey] .= '[' . $symbols['plus']. '+]{0,1}[0-9]{1,}(\\' . $symbols['decimal'] . '[0-9]{1,})*[eE][' . $symbols['plus']. '+]{0,1}[0-9]{1,}';
0616                 } else if (($pattern == '-#E0') || ($pattern == '-#E00')) {
0617                     $regex[$pkey] .= '[' . $symbols['minus']. '-]{0,1}[0-9]{1,}(\\' . $symbols['decimal'] . '[0-9]{1,})*[eE][' . $symbols['minus']. '-]{0,1}[0-9]{1,}';
0618                 } else {
0619                     throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 5):"' . $pattern . '"');
0620                 }
0621             }
0622 
0623             if (!empty($end)) {
0624                 if ($end == '###') {
0625                     $regex[$pkey] .= '(\\' . $symbols['decimal'] . '{1}[0-9]{1,}){0,1}';
0626                 } else if ($end == '###-') {
0627                     $regex[$pkey] .= '(\\' . $symbols['decimal'] . '{1}[0-9]{1,}){0,1}[' . $symbols['minus']. '-]';
0628                 } else {
0629                     throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 6):"' . $pattern . '"');
0630                 }
0631             }
0632 
0633             $regex[$pkey] .= '$/u';
0634         }
0635 
0636         return $regex;
0637     }
0638 
0639     /**
0640      * Alias for getNumber
0641      *
0642      * @param   string  $input    Number to localize
0643      * @param   array   $options  Options: locale, precision. See {@link setOptions()} for details.
0644      * @return  float
0645      */
0646     public static function getFloat($input, array $options = array())
0647     {
0648         return floatval(self::getNumber($input, $options));
0649     }
0650 
0651     /**
0652      * Returns a locale formatted integer number
0653      * Alias for toNumber()
0654      *
0655      * @param   string  $value    Number to normalize
0656      * @param   array   $options  Options: locale, precision. See {@link setOptions()} for details.
0657      * @return  string  Locale formatted number
0658      */
0659     public static function toFloat($value, array $options = array())
0660     {
0661         $options['number_format'] = Zend_Locale_Format::STANDARD;
0662         return self::toNumber($value, $options);
0663     }
0664 
0665     /**
0666      * Returns if a float was found
0667      * Alias for isNumber()
0668      *
0669      * @param   string $value  Localized number string
0670      * @param   array $options Options: locale. See {@link setOptions()} for details.
0671      * @return  boolean        Returns true if a number was found
0672      */
0673     public static function isFloat($value, array $options = array())
0674     {
0675         return self::isNumber($value, $options);
0676     }
0677 
0678     /**
0679      * Returns the first found integer from an string
0680      * Parsing depends on given locale (grouping and decimal)
0681      *
0682      * Examples for input:
0683      * '  2345.4356,1234' = 23455456
0684      * '+23,3452.123' = 233452
0685      * ' 12343 ' = 12343
0686      * '-9456km' = -9456
0687      * '0' = 0
0688      * '(-){0,1}(\d+(\.){0,1})*(\,){0,1})\d+'
0689      *
0690      * @param   string   $input    Input string to parse for numbers
0691      * @param   array    $options  Options: locale. See {@link setOptions()} for details.
0692      * @return  integer            Returns the extracted number
0693      */
0694     public static function getInteger($input, array $options = array())
0695     {
0696         $options['precision'] = 0;
0697         return intval(self::getFloat($input, $options));
0698     }
0699 
0700     /**
0701      * Returns a localized number
0702      *
0703      * @param   string  $value    Number to normalize
0704      * @param   array   $options  Options: locale. See {@link setOptions()} for details.
0705      * @return  string            Locale formatted number
0706      */
0707     public static function toInteger($value, array $options = array())
0708     {
0709         $options['precision'] = 0;
0710         $options['number_format'] = Zend_Locale_Format::STANDARD;
0711         return self::toNumber($value, $options);
0712     }
0713 
0714     /**
0715      * Returns if a integer was found
0716      *
0717      * @param  string $value Localized number string
0718      * @param  array $options Options: locale. See {@link setOptions()} for details.
0719      * @return boolean Returns true if a integer was found
0720      */
0721     public static function isInteger($value, array $options = array())
0722     {
0723         if (!self::isNumber($value, $options)) {
0724             return false;
0725         }
0726 
0727         if (self::getInteger($value, $options) == self::getFloat($value, $options)) {
0728             return true;
0729         }
0730 
0731         return false;
0732     }
0733 
0734     /**
0735      * Converts a format string from PHP's date format to ISO format
0736      * Remember that Zend Date always returns localized string, so a month name which returns the english
0737      * month in php's date() will return the translated month name with this function... use 'en' as locale
0738      * if you are in need of the original english names
0739      *
0740      * The conversion has the following restrictions:
0741      * 'a', 'A' - Meridiem is not explicit upper/lowercase, you have to upper/lowercase the translated value yourself
0742      *
0743      * @param  string  $format  Format string in PHP's date format
0744      * @return string           Format string in ISO format
0745      */
0746     public static function convertPhpToIsoFormat($format)
0747     {
0748         if ($format === null) {
0749             return null;
0750         }
0751 
0752         $convert = array(
0753             'd' => 'dd'  , 'D' => 'EE'  , 'j' => 'd'   , 'l' => 'EEEE',
0754             'N' => 'eee' , 'S' => 'SS'  , 'w' => 'e'   , 'z' => 'D'   ,
0755             'W' => 'ww'  , 'F' => 'MMMM', 'm' => 'MM'  , 'M' => 'MMM' ,
0756             'n' => 'M'   , 't' => 'ddd' , 'L' => 'l'   , 'o' => 'YYYY',
0757             'Y' => 'yyyy', 'y' => 'yy'  , 'a' => 'a'   , 'A' => 'a'   ,
0758             'B' => 'B'   , 'g' => 'h'   , 'G' => 'H'   , 'h' => 'hh'  ,
0759             'H' => 'HH'  , 'i' => 'mm'  , 's' => 'ss'  , 'e' => 'zzzz',
0760             'I' => 'I'   , 'O' => 'Z'   , 'P' => 'ZZZZ', 'T' => 'z'   ,
0761             'Z' => 'X'   , 'c' => 'yyyy-MM-ddTHH:mm:ssZZZZ', 'r' => 'r',
0762             'U' => 'U',
0763         );
0764         $escaped = false;
0765         $inEscapedString = false;
0766         $converted = array();
0767         foreach (str_split($format) as $char) {
0768             if (!$escaped && $char == '\\') {
0769                 // Next char will be escaped: let's remember it
0770                 $escaped = true;
0771             } elseif ($escaped) {
0772                 if (!$inEscapedString) {
0773                     // First escaped string: start the quoted chunk
0774                     $converted[] = "'";
0775                     $inEscapedString = true;
0776                 }
0777                 // Since the previous char was a \ and we are in the quoted
0778                 // chunk, let's simply add $char as it is
0779                 $converted[] = $char;
0780                 $escaped = false;
0781             } elseif ($char == "'") {
0782                 // Single quotes need to be escaped like this
0783                 $converted[] = "''";
0784             } else {
0785                 if ($inEscapedString) {
0786                     // Close the single-quoted chunk
0787                     $converted[] = "'";
0788                     $inEscapedString = false;
0789                 }
0790                 // Convert the unescaped char if needed
0791                 if (isset($convert[$char])) {
0792                     $converted[] = $convert[$char];
0793                 } else {
0794                     $converted[] = $char;
0795                 }
0796             }
0797         }
0798 
0799         return implode($converted);
0800     }
0801 
0802     /**
0803      * Parse date and split in named array fields
0804      *
0805      * @param  string $date    Date string to parse
0806      * @param  array  $options Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
0807      * @return array Possible array members: day, month, year, hour, minute, second, fixed, format
0808      * @throws Zend_Locale_Exception
0809      */
0810     private static function _parseDate($date, $options)
0811     {
0812         if (!self::_getUniCodeSupport()) {
0813             trigger_error("Sorry, your PCRE extension does not support UTF8 which is needed for the I18N core", E_USER_NOTICE);
0814         }
0815 
0816         $options = self::_checkOptions($options) + self::$_options;
0817         $test = array('h', 'H', 'm', 's', 'y', 'Y', 'M', 'd', 'D', 'E', 'S', 'l', 'B', 'I',
0818                        'X', 'r', 'U', 'G', 'w', 'e', 'a', 'A', 'Z', 'z', 'v');
0819 
0820         $format = $options['date_format'];
0821         $number = $date; // working copy
0822         $result['date_format'] = $format; // save the format used to normalize $number (convenience)
0823         $result['locale'] = $options['locale']; // save the locale used to normalize $number (convenience)
0824 
0825         $oenc = self::_getEncoding();
0826         self::_setEncoding('UTF-8');
0827         $day   = iconv_strpos($format, 'd');
0828         $month = iconv_strpos($format, 'M');
0829         $year  = iconv_strpos($format, 'y');
0830         $hour  = iconv_strpos($format, 'H');
0831         $min   = iconv_strpos($format, 'm');
0832         $sec   = iconv_strpos($format, 's');
0833         $am    = null;
0834         if ($hour === false) {
0835             $hour = iconv_strpos($format, 'h');
0836         }
0837         if ($year === false) {
0838             $year = iconv_strpos($format, 'Y');
0839         }
0840         if ($day === false) {
0841             $day = iconv_strpos($format, 'E');
0842             if ($day === false) {
0843                 $day = iconv_strpos($format, 'D');
0844             }
0845         }
0846 
0847         if ($day !== false) {
0848             $parse[$day]   = 'd';
0849             if (!empty($options['locale']) && ($options['locale'] !== 'root') &&
0850                 (!is_object($options['locale']) || ((string) $options['locale'] !== 'root'))) {
0851                 // erase day string
0852                     $daylist = Zend_Locale_Data::getList($options['locale'], 'day');
0853                 foreach($daylist as $key => $name) {
0854                     if (iconv_strpos($number, $name) !== false) {
0855                         $number = str_replace($name, "EEEE", $number);
0856                         break;
0857                     }
0858                 }
0859             }
0860         }
0861         $position = false;
0862 
0863         if ($month !== false) {
0864             $parse[$month] = 'M';
0865             if (!empty($options['locale']) && ($options['locale'] !== 'root') &&
0866                 (!is_object($options['locale']) || ((string) $options['locale'] !== 'root'))) {
0867                     // prepare to convert month name to their numeric equivalents, if requested,
0868                     // and we have a $options['locale']
0869                     $position = self::_replaceMonth($number, Zend_Locale_Data::getList($options['locale'],
0870                         'month'));
0871                 if ($position === false) {
0872                     $position = self::_replaceMonth($number, Zend_Locale_Data::getList($options['locale'],
0873                         'month', array('gregorian', 'format', 'abbreviated')));
0874                 }
0875             }
0876         }
0877         if ($year !== false) {
0878             $parse[$year]  = 'y';
0879         }
0880         if ($hour !== false) {
0881             $parse[$hour] = 'H';
0882         }
0883         if ($min !== false) {
0884             $parse[$min] = 'm';
0885         }
0886         if ($sec !== false) {
0887             $parse[$sec] = 's';
0888         }
0889 
0890         if (empty($parse)) {
0891             self::_setEncoding($oenc);
0892             // require_once 'Zend/Locale/Exception.php';
0893             throw new Zend_Locale_Exception("Unknown date format, neither date nor time in '" . $format . "' found");
0894         }
0895         ksort($parse);
0896 
0897         // get daytime
0898         if (iconv_strpos($format, 'a') !== false) {
0899             if (iconv_strpos(strtoupper($number), strtoupper(Zend_Locale_Data::getContent($options['locale'], 'am'))) !== false) {
0900                 $am = true;
0901             } else if (iconv_strpos(strtoupper($number), strtoupper(Zend_Locale_Data::getContent($options['locale'], 'pm'))) !== false) {
0902                 $am = false;
0903             }
0904         }
0905 
0906         // split number parts
0907         $split = false;
0908         preg_match_all('/\d+/u', $number, $splitted);
0909 
0910         if (count($splitted[0]) == 0) {
0911             self::_setEncoding($oenc);
0912             // require_once 'Zend/Locale/Exception.php';
0913             throw new Zend_Locale_Exception("No date part in '$date' found.");
0914         }
0915         if (count($splitted[0]) == 1) {
0916             $split = 0;
0917         }
0918         $cnt = 0;
0919         foreach($parse as $key => $value) {
0920 
0921             switch($value) {
0922                 case 'd':
0923                     if ($split === false) {
0924                         if (count($splitted[0]) > $cnt) {
0925                             $result['day']    = $splitted[0][$cnt];
0926                         }
0927                     } else {
0928                         $result['day'] = iconv_substr($splitted[0][0], $split, 2);
0929                         $split += 2;
0930                     }
0931                     ++$cnt;
0932                     break;
0933                 case 'M':
0934                     if ($split === false) {
0935                         if (count($splitted[0]) > $cnt) {
0936                             $result['month']  = $splitted[0][$cnt];
0937                         }
0938                     } else {
0939                         $result['month'] = iconv_substr($splitted[0][0], $split, 2);
0940                         $split += 2;
0941                     }
0942                     ++$cnt;
0943                     break;
0944                 case 'y':
0945                     $length = 2;
0946                     if ((iconv_substr($format, $year, 4) == 'yyyy')
0947                      || (iconv_substr($format, $year, 4) == 'YYYY')) {
0948                         $length = 4;
0949                     }
0950 
0951                     if ($split === false) {
0952                         if (count($splitted[0]) > $cnt) {
0953                             $result['year']   = $splitted[0][$cnt];
0954                         }
0955                     } else {
0956                         $result['year']   = iconv_substr($splitted[0][0], $split, $length);
0957                         $split += $length;
0958                     }
0959 
0960                     ++$cnt;
0961                     break;
0962                 case 'H':
0963                     if ($split === false) {
0964                         if (count($splitted[0]) > $cnt) {
0965                             $result['hour']   = $splitted[0][$cnt];
0966                         }
0967                     } else {
0968                         $result['hour']   = iconv_substr($splitted[0][0], $split, 2);
0969                         $split += 2;
0970                     }
0971                     ++$cnt;
0972                     break;
0973                 case 'm':
0974                     if ($split === false) {
0975                         if (count($splitted[0]) > $cnt) {
0976                             $result['minute'] = $splitted[0][$cnt];
0977                         }
0978                     } else {
0979                         $result['minute'] = iconv_substr($splitted[0][0], $split, 2);
0980                         $split += 2;
0981                     }
0982                     ++$cnt;
0983                     break;
0984                 case 's':
0985                     if ($split === false) {
0986                         if (count($splitted[0]) > $cnt) {
0987                             $result['second'] = $splitted[0][$cnt];
0988                         }
0989                     } else {
0990                         $result['second'] = iconv_substr($splitted[0][0], $split, 2);
0991                         $split += 2;
0992                     }
0993                     ++$cnt;
0994                     break;
0995             }
0996         }
0997 
0998         // AM/PM correction
0999         if ($hour !== false) {
1000             if (($am === true) and ($result['hour'] == 12)){
1001                 $result['hour'] = 0;
1002             } else if (($am === false) and ($result['hour'] != 12)) {
1003                 $result['hour'] += 12;
1004             }
1005         }
1006 
1007         if ($options['fix_date'] === true) {
1008             $result['fixed'] = 0; // nothing has been "fixed" by swapping date parts around (yet)
1009         }
1010 
1011         if ($day !== false) {
1012             // fix false month
1013             if (isset($result['day']) and isset($result['month'])) {
1014                 if (($position !== false) and ((iconv_strpos($date, $result['day']) === false) or
1015                                                (isset($result['year']) and (iconv_strpos($date, $result['year']) === false)))) {
1016                     if ($options['fix_date'] !== true) {
1017                         self::_setEncoding($oenc);
1018                         // require_once 'Zend/Locale/Exception.php';
1019                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '" . $format
1020                             . "' (false month, $position, $month)");
1021                     }
1022                     $temp = $result['day'];
1023                     $result['day']   = $result['month'];
1024                     $result['month'] = $temp;
1025                     $result['fixed'] = 1;
1026                 }
1027             }
1028 
1029             // fix switched values d <> y
1030             if (isset($result['day']) and isset($result['year'])) {
1031                 if ($result['day'] > 31) {
1032                     if ($options['fix_date'] !== true) {
1033                         self::_setEncoding($oenc);
1034                         // require_once 'Zend/Locale/Exception.php';
1035                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '"
1036                                                       . $format . "' (d <> y)");
1037                     }
1038                     $temp = $result['year'];
1039                     $result['year'] = $result['day'];
1040                     $result['day']  = $temp;
1041                     $result['fixed'] = 2;
1042                 }
1043             }
1044 
1045             // fix switched values M <> y
1046             if (isset($result['month']) and isset($result['year'])) {
1047                 if ($result['month'] > 31) {
1048                     if ($options['fix_date'] !== true) {
1049                         self::_setEncoding($oenc);
1050                         // require_once 'Zend/Locale/Exception.php';
1051                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '"
1052                                                       . $format . "' (M <> y)");
1053                     }
1054                     $temp = $result['year'];
1055                     $result['year']  = $result['month'];
1056                     $result['month'] = $temp;
1057                     $result['fixed'] = 3;
1058                 }
1059             }
1060 
1061             // fix switched values M <> d
1062             if (isset($result['month']) and isset($result['day'])) {
1063                 if ($result['month'] > 12) {
1064                     if ($options['fix_date'] !== true || $result['month'] > 31) {
1065                         self::_setEncoding($oenc);
1066                         // require_once 'Zend/Locale/Exception.php';
1067                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '"
1068                                                       . $format . "' (M <> d)");
1069                     }
1070                     $temp = $result['day'];
1071                     $result['day']   = $result['month'];
1072                     $result['month'] = $temp;
1073                     $result['fixed'] = 4;
1074                 }
1075             }
1076         }
1077 
1078         if (isset($result['year'])) {
1079             if (((iconv_strlen($result['year']) == 2) && ($result['year'] < 10)) ||
1080                 (((iconv_strpos($format, 'yy') !== false) && (iconv_strpos($format, 'yyyy') === false)) ||
1081                 ((iconv_strpos($format, 'YY') !== false) && (iconv_strpos($format, 'YYYY') === false)))) {
1082                 if (($result['year'] >= 0) && ($result['year'] < 100)) {
1083                     if ($result['year'] < 70) {
1084                         $result['year'] = (int) $result['year'] + 100;
1085                     }
1086 
1087                     $result['year'] = (int) $result['year'] + 1900;
1088                 }
1089             }
1090         }
1091 
1092         self::_setEncoding($oenc);
1093         return $result;
1094     }
1095 
1096     /**
1097      * Search $number for a month name found in $monthlist, and replace if found.
1098      *
1099      * @param  string  $number     Date string (modified)
1100      * @param  array   $monthlist  List of month names
1101      *
1102      * @return int|false           Position of replaced string (false if nothing replaced)
1103      */
1104     protected static function _replaceMonth(&$number, $monthlist)
1105     {
1106         // If $locale was invalid, $monthlist will default to a "root" identity
1107         // mapping for each month number from 1 to 12.
1108         // If no $locale was given, or $locale was invalid, do not use this identity mapping to normalize.
1109         // Otherwise, translate locale aware month names in $number to their numeric equivalents.
1110         $position = false;
1111         if ($monthlist && $monthlist[1] != 1) {
1112             foreach($monthlist as $key => $name) {
1113                 if (($position = iconv_strpos($number, $name, 0, 'UTF-8')) !== false) {
1114                     $number   = str_ireplace($name, $key, $number);
1115                     return $position;
1116                 }
1117             }
1118         }
1119 
1120         return false;
1121     }
1122 
1123     /**
1124      * Returns the default date format for $locale.
1125      *
1126      * @param  string|Zend_Locale  $locale  OPTIONAL Locale of $number, possibly in string form (e.g. 'de_AT')
1127      * @return string  format
1128      * @throws Zend_Locale_Exception  throws an exception when locale data is broken
1129      */
1130     public static function getDateFormat($locale = null)
1131     {
1132         $format = Zend_Locale_Data::getContent($locale, 'date');
1133         if (empty($format)) {
1134             // require_once 'Zend/Locale/Exception.php';
1135             throw new Zend_Locale_Exception("failed to receive data from locale $locale");
1136         }
1137 
1138         return $format;
1139     }
1140 
1141     /**
1142      * Returns an array with the normalized date from an locale date
1143      * a input of 10.01.2006 without a $locale would return:
1144      * array ('day' => 10, 'month' => 1, 'year' => 2006)
1145      * The 'locale' option is only used to convert human readable day
1146      * and month names to their numeric equivalents.
1147      * The 'format' option allows specification of self-defined date formats,
1148      * when not using the default format for the 'locale'.
1149      *
1150      * @param   string  $date     Date string
1151      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
1152      * @return  array             Possible array members: day, month, year, hour, minute, second, fixed, format
1153      */
1154     public static function getDate($date, array $options = array())
1155     {
1156         $options = self::_checkOptions($options) + self::$_options;
1157         if (empty($options['date_format'])) {
1158             $options['format_type'] = 'iso';
1159             $options['date_format'] = self::getDateFormat($options['locale']);
1160         }
1161 
1162         return self::_parseDate($date, $options);
1163     }
1164 
1165     /**
1166      * Returns if the given datestring contains all date parts from the given format.
1167      * If no format is given, the default date format from the locale is used
1168      * If you want to check if the date is a proper date you should use Zend_Date::isDate()
1169      *
1170      * @param   string  $date     Date string
1171      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
1172      * @return  boolean
1173      */
1174     public static function checkDateFormat($date, array $options = array())
1175     {
1176         try {
1177             $date = self::getDate($date, $options);
1178         } catch (Exception $e) {
1179             return false;
1180         }
1181 
1182         if (empty($options['date_format'])) {
1183             $options['format_type'] = 'iso';
1184             $options['date_format'] = self::getDateFormat(isset($options['locale']) ? $options['locale'] : null);
1185         }
1186         $options = self::_checkOptions($options) + self::$_options;
1187 
1188         // day expected but not parsed
1189         if ((iconv_strpos($options['date_format'], 'd', 0, 'UTF-8') !== false) and (!isset($date['day']) or ($date['day'] === ""))) {
1190             return false;
1191         }
1192 
1193         // month expected but not parsed
1194         if ((iconv_strpos($options['date_format'], 'M', 0, 'UTF-8') !== false) and (!isset($date['month']) or ($date['month'] === ""))) {
1195             return false;
1196         }
1197 
1198         // year expected but not parsed
1199         if (((iconv_strpos($options['date_format'], 'Y', 0, 'UTF-8') !== false) or
1200              (iconv_strpos($options['date_format'], 'y', 0, 'UTF-8') !== false)) and (!isset($date['year']) or ($date['year'] === ""))) {
1201             return false;
1202         }
1203 
1204         // second expected but not parsed
1205         if ((iconv_strpos($options['date_format'], 's', 0, 'UTF-8') !== false) and (!isset($date['second']) or ($date['second'] === ""))) {
1206             return false;
1207         }
1208 
1209         // minute expected but not parsed
1210         if ((iconv_strpos($options['date_format'], 'm', 0, 'UTF-8') !== false) and (!isset($date['minute']) or ($date['minute'] === ""))) {
1211             return false;
1212         }
1213 
1214         // hour expected but not parsed
1215         if (((iconv_strpos($options['date_format'], 'H', 0, 'UTF-8') !== false) or
1216              (iconv_strpos($options['date_format'], 'h', 0, 'UTF-8') !== false)) and (!isset($date['hour']) or ($date['hour'] === ""))) {
1217             return false;
1218         }
1219 
1220         return true;
1221     }
1222 
1223     /**
1224      * Returns the default time format for $locale.
1225      *
1226      * @param  string|Zend_Locale $locale OPTIONAL Locale of $number, possibly in string form (e.g. 'de_AT')
1227      * @return string  format
1228      * @throws Zend_Locale_Exception
1229      */
1230     public static function getTimeFormat($locale = null)
1231     {
1232         $format = Zend_Locale_Data::getContent($locale, 'time');
1233         if (empty($format)) {
1234             // require_once 'Zend/Locale/Exception.php';
1235             throw new Zend_Locale_Exception("failed to receive data from locale $locale");
1236         }
1237         return $format;
1238     }
1239 
1240     /**
1241      * Returns an array with 'hour', 'minute', and 'second' elements extracted from $time
1242      * according to the order described in $format.  For a format of 'H:i:s', and
1243      * an input of 11:20:55, getTime() would return:
1244      * array ('hour' => 11, 'minute' => 20, 'second' => 55)
1245      * The optional $locale parameter may be used to help extract times from strings
1246      * containing both a time and a day or month name.
1247      *
1248      * @param   string  $time     Time string
1249      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
1250      * @return  array             Possible array members: day, month, year, hour, minute, second, fixed, format
1251      */
1252     public static function getTime($time, array $options = array())
1253     {
1254         $options = self::_checkOptions($options) + self::$_options;
1255         if (empty($options['date_format'])) {
1256             $options['format_type'] = 'iso';
1257             $options['date_format'] = self::getTimeFormat($options['locale']);
1258         }
1259         return self::_parseDate($time, $options);
1260     }
1261 
1262     /**
1263      * Returns the default datetime format for $locale.
1264      *
1265      * @param  string|Zend_Locale $locale OPTIONAL Locale of $number, possibly in string form (e.g. 'de_AT')
1266      * @return string  format
1267      * @throws Zend_Locale_Exception
1268      */
1269     public static function getDateTimeFormat($locale = null)
1270     {
1271         $format = Zend_Locale_Data::getContent($locale, 'datetime');
1272         if (empty($format)) {
1273             // require_once 'Zend/Locale/Exception.php';
1274             throw new Zend_Locale_Exception("failed to receive data from locale $locale");
1275         }
1276         return $format;
1277     }
1278 
1279     /**
1280      * Returns an array with 'year', 'month', 'day', 'hour', 'minute', and 'second' elements
1281      * extracted from $datetime according to the order described in $format.  For a format of 'd.M.y H:i:s',
1282      * and an input of 10.05.1985 11:20:55, getDateTime() would return:
1283      * array ('year' => 1985, 'month' => 5, 'day' => 10, 'hour' => 11, 'minute' => 20, 'second' => 55)
1284      * The optional $locale parameter may be used to help extract times from strings
1285      * containing both a time and a day or month name.
1286      *
1287      * @param   string  $datetime DateTime string
1288      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
1289      * @return  array             Possible array members: day, month, year, hour, minute, second, fixed, format
1290      */
1291     public static function getDateTime($datetime, array $options = array())
1292     {
1293         $options = self::_checkOptions($options) + self::$_options;
1294         if (empty($options['date_format'])) {
1295             $options['format_type'] = 'iso';
1296             $options['date_format'] = self::getDateTimeFormat($options['locale']);
1297         }
1298         return self::_parseDate($datetime, $options);
1299     }
1300 
1301     /**
1302      * Internal method to detect of Unicode supports UTF8
1303      * which should be enabled within vanilla php installations
1304      *
1305      * @return boolean
1306      */
1307     protected static function _getUniCodeSupport()
1308     {
1309         return (@preg_match('/\pL/u', 'a')) ? true : false;
1310     }
1311 
1312     /**
1313      * Internal method to retrieve the current encoding via the ini setting
1314      * default_charset for PHP >= 5.6 or iconv_get_encoding otherwise.
1315      *
1316      * @return string
1317      */
1318     protected static function _getEncoding()
1319     {
1320         $oenc = PHP_VERSION_ID < 50600
1321             ? iconv_get_encoding('internal_encoding')
1322             : ini_get('default_charset');
1323 
1324         return $oenc;
1325     }
1326 
1327     /**
1328      * Internal method to set the encoding via the ini setting
1329      * default_charset for PHP >= 5.6 or iconv_set_encoding otherwise.
1330      *
1331      * @param string $encoding
1332      * @return void
1333      */
1334     protected static function _setEncoding($encoding)
1335     {
1336         if (PHP_VERSION_ID < 50600) {
1337             iconv_set_encoding('internal_encoding', $encoding);
1338         } else {
1339             ini_set('default_charset', $encoding);
1340         }
1341     }
1342 }