web/lib/Zend/Locale/Format.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Locale
       
    17  * @subpackage Format
       
    18  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    19  * @version    $Id: Format.php 22808 2010-08-08 09:38:42Z thomas $
       
    20  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    21  */
       
    22 
       
    23 /**
       
    24  * include needed classes
       
    25  */
       
    26 require_once 'Zend/Locale/Data.php';
       
    27 
       
    28 /**
       
    29  * @category   Zend
       
    30  * @package    Zend_Locale
       
    31  * @subpackage Format
       
    32  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    33  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    34  */
       
    35 class Zend_Locale_Format
       
    36 {
       
    37     const STANDARD   = 'auto';
       
    38 
       
    39     private static $_options = array('date_format'   => null,
       
    40                                      'number_format' => null,
       
    41                                      'format_type'   => 'iso',
       
    42                                      'fix_date'      => false,
       
    43                                      'locale'        => null,
       
    44                                      'cache'         => null,
       
    45                                      'disableCache'  => false,
       
    46                                      'precision'     => null);
       
    47 
       
    48     /**
       
    49      * Sets class wide options, if no option was given, the actual set options will be returned
       
    50      * The 'precision' option of a value is used to truncate or stretch extra digits. -1 means not to touch the extra digits.
       
    51      * The 'locale' option helps when parsing numbers and dates using separators and month names.
       
    52      * The date format 'format_type' option selects between CLDR/ISO date format specifier tokens and PHP's date() tokens.
       
    53      * The 'fix_date' option enables or disables heuristics that attempt to correct invalid dates.
       
    54      * The 'number_format' option can be used to specify a default number format string
       
    55      * The 'date_format' option can be used to specify a default date format string, but beware of using getDate(),
       
    56      * checkDateFormat() and getTime() after using setOptions() with a 'format'.  To use these four methods
       
    57      * with the default date format for a locale, use array('date_format' => null, 'locale' => $locale) for their options.
       
    58      *
       
    59      * @param  array  $options  Array of options, keyed by option name: format_type = 'iso' | 'php', fix_date = true | false,
       
    60      *                          locale = Zend_Locale | locale string, precision = whole number between -1 and 30
       
    61      * @throws Zend_Locale_Exception
       
    62      * @return Options array if no option was given
       
    63      */
       
    64     public static function setOptions(array $options = array())
       
    65     {
       
    66         self::$_options = self::_checkOptions($options) + self::$_options;
       
    67         return self::$_options;
       
    68     }
       
    69 
       
    70     /**
       
    71      * Internal function for checking the options array of proper input values
       
    72      * See {@link setOptions()} for details.
       
    73      *
       
    74      * @param  array  $options  Array of options, keyed by option name: format_type = 'iso' | 'php', fix_date = true | false,
       
    75      *                          locale = Zend_Locale | locale string, precision = whole number between -1 and 30
       
    76      * @throws Zend_Locale_Exception
       
    77      * @return Options array if no option was given
       
    78      */
       
    79     private static function _checkOptions(array $options = array())
       
    80     {
       
    81         if (count($options) == 0) {
       
    82             return self::$_options;
       
    83         }
       
    84         foreach ($options as $name => $value) {
       
    85             $name  = strtolower($name);
       
    86             if ($name !== 'locale') {
       
    87                 if (gettype($value) === 'string') {
       
    88                     $value = strtolower($value);
       
    89                 }
       
    90             }
       
    91 
       
    92             switch($name) {
       
    93                 case 'number_format' :
       
    94                     if ($value == Zend_Locale_Format::STANDARD) {
       
    95                         $locale = self::$_options['locale'];
       
    96                         if (isset($options['locale'])) {
       
    97                             $locale = $options['locale'];
       
    98                         }
       
    99                         $options['number_format'] = Zend_Locale_Data::getContent($locale, 'decimalnumber');
       
   100                     } else if ((gettype($value) !== 'string') and ($value !== NULL)) {
       
   101                         require_once 'Zend/Locale/Exception.php';
       
   102                         throw new Zend_Locale_Exception("Unknown number format type '" . gettype($value) . "'. "
       
   103                             . "Format '$value' must be a valid number format string.");
       
   104                     }
       
   105                     break;
       
   106 
       
   107                 case 'date_format' :
       
   108                     if ($value == Zend_Locale_Format::STANDARD) {
       
   109                         $locale = self::$_options['locale'];
       
   110                         if (isset($options['locale'])) {
       
   111                             $locale = $options['locale'];
       
   112                         }
       
   113                         $options['date_format'] = Zend_Locale_Format::getDateFormat($locale);
       
   114                     } else if ((gettype($value) !== 'string') and ($value !== NULL)) {
       
   115                         require_once 'Zend/Locale/Exception.php';
       
   116                         throw new Zend_Locale_Exception("Unknown dateformat type '" . gettype($value) . "'. "
       
   117                             . "Format '$value' must be a valid ISO or PHP date format string.");
       
   118                     } else {
       
   119                         if (((isset($options['format_type']) === true) and ($options['format_type'] == 'php')) or
       
   120                             ((isset($options['format_type']) === false) and (self::$_options['format_type'] == 'php'))) {
       
   121                             $options['date_format'] = Zend_Locale_Format::convertPhpToIsoFormat($value);
       
   122                         }
       
   123                     }
       
   124                     break;
       
   125 
       
   126                 case 'format_type' :
       
   127                     if (($value != 'php') && ($value != 'iso')) {
       
   128                         require_once 'Zend/Locale/Exception.php';
       
   129                         throw new Zend_Locale_Exception("Unknown date format type '$value'. Only 'iso' and 'php'"
       
   130                            . " are supported.");
       
   131                     }
       
   132                     break;
       
   133 
       
   134                 case 'fix_date' :
       
   135                     if (($value !== true) && ($value !== false)) {
       
   136                         require_once 'Zend/Locale/Exception.php';
       
   137                         throw new Zend_Locale_Exception("Enabling correction of dates must be either true or false"
       
   138                             . "(fix_date='$value').");
       
   139                     }
       
   140                     break;
       
   141 
       
   142                 case 'locale' :
       
   143                     $options['locale'] = Zend_Locale::findLocale($value);
       
   144                     break;
       
   145 
       
   146                 case 'cache' :
       
   147                     if ($value instanceof Zend_Cache_Core) {
       
   148                         Zend_Locale_Data::setCache($value);
       
   149                     }
       
   150                     break;
       
   151 
       
   152                 case 'disablecache' :
       
   153                     Zend_Locale_Data::disableCache($value);
       
   154                     break;
       
   155 
       
   156                 case 'precision' :
       
   157                     if ($value === NULL) {
       
   158                         $value = -1;
       
   159                     }
       
   160 
       
   161                     if (($value < -1) || ($value > 30)) {
       
   162                         require_once 'Zend/Locale/Exception.php';
       
   163                         throw new Zend_Locale_Exception("'$value' precision is not a whole number less than 30.");
       
   164                     }
       
   165                     break;
       
   166 
       
   167                 default:
       
   168                     require_once 'Zend/Locale/Exception.php';
       
   169                     throw new Zend_Locale_Exception("Unknown option: '$name' = '$value'");
       
   170                     break;
       
   171 
       
   172             }
       
   173         }
       
   174 
       
   175         return $options;
       
   176     }
       
   177 
       
   178     /**
       
   179      * Changes the numbers/digits within a given string from one script to another
       
   180      * 'Decimal' representated the stardard numbers 0-9, if a script does not exist
       
   181      * an exception will be thrown.
       
   182      *
       
   183      * Examples for conversion from Arabic to Latin numerals:
       
   184      *   convertNumerals('١١٠ Tests', 'Arab'); -> returns '100 Tests'
       
   185      * Example for conversion from Latin to Arabic numerals:
       
   186      *   convertNumerals('100 Tests', 'Latn', 'Arab'); -> returns '١١٠ Tests'
       
   187      *
       
   188      * @param  string  $input  String to convert
       
   189      * @param  string  $from   Script to parse, see {@link Zend_Locale::getScriptList()} for details.
       
   190      * @param  string  $to     OPTIONAL Script to convert to
       
   191      * @return string  Returns the converted input
       
   192      * @throws Zend_Locale_Exception
       
   193      */
       
   194     public static function convertNumerals($input, $from, $to = null)
       
   195     {
       
   196         if (!self::_getUniCodeSupport()) {
       
   197             trigger_error("Sorry, your PCRE extension does not support UTF8 which is needed for the I18N core", E_USER_NOTICE);
       
   198         }
       
   199 
       
   200         $from   = strtolower($from);
       
   201         $source = Zend_Locale_Data::getContent('en', 'numberingsystem', $from);
       
   202         if (empty($source)) {
       
   203             require_once 'Zend/Locale/Exception.php';
       
   204             throw new Zend_Locale_Exception("Unknown script '$from'. Use 'Latn' for digits 0,1,2,3,4,5,6,7,8,9.");
       
   205         }
       
   206 
       
   207         if ($to !== null) {
       
   208             $to     = strtolower($to);
       
   209             $target = Zend_Locale_Data::getContent('en', 'numberingsystem', $to);
       
   210             if (empty($target)) {
       
   211                 require_once 'Zend/Locale/Exception.php';
       
   212                 throw new Zend_Locale_Exception("Unknown script '$to'. Use 'Latn' for digits 0,1,2,3,4,5,6,7,8,9.");
       
   213             }
       
   214         } else {
       
   215             $target = '0123456789';
       
   216         }
       
   217 
       
   218         for ($x = 0; $x < 10; ++$x) {
       
   219             $asource[$x] = "/" . iconv_substr($source, $x, 1, 'UTF-8') . "/u";
       
   220             $atarget[$x] = iconv_substr($target, $x, 1, 'UTF-8');
       
   221         }
       
   222 
       
   223         return preg_replace($asource, $atarget, $input);
       
   224     }
       
   225 
       
   226     /**
       
   227      * Returns the normalized number from a localized one
       
   228      * Parsing depends on given locale (grouping and decimal)
       
   229      *
       
   230      * Examples for input:
       
   231      * '2345.4356,1234' = 23455456.1234
       
   232      * '+23,3452.123' = 233452.123
       
   233      * '12343 ' = 12343
       
   234      * '-9456' = -9456
       
   235      * '0' = 0
       
   236      *
       
   237      * @param  string $input    Input string to parse for numbers
       
   238      * @param  array  $options  Options: locale, precision. See {@link setOptions()} for details.
       
   239      * @return string Returns the extracted number
       
   240      * @throws Zend_Locale_Exception
       
   241      */
       
   242     public static function getNumber($input, array $options = array())
       
   243     {
       
   244         $options = self::_checkOptions($options) + self::$_options;
       
   245         if (!is_string($input)) {
       
   246             return $input;
       
   247         }
       
   248 
       
   249         if (!self::isNumber($input, $options)) {
       
   250             require_once 'Zend/Locale/Exception.php';
       
   251             throw new Zend_Locale_Exception('No localized value in ' . $input . ' found, or the given number does not match the localized format');
       
   252         }
       
   253 
       
   254         // Get correct signs for this locale
       
   255         $symbols = Zend_Locale_Data::getList($options['locale'],'symbols');
       
   256         // Change locale input to be default number
       
   257         if ((strpos($input, $symbols['minus']) !== false) ||
       
   258             (strpos($input, '-') !== false)) {
       
   259             $input = strtr($input, array($symbols['minus'] => '', '-' => ''));
       
   260             $input = '-' . $input;
       
   261         }
       
   262 
       
   263         $input = str_replace($symbols['group'],'', $input);
       
   264         if (strpos($input, $symbols['decimal']) !== false) {
       
   265             if ($symbols['decimal'] != '.') {
       
   266                 $input = str_replace($symbols['decimal'], ".", $input);
       
   267             }
       
   268 
       
   269             $pre = substr($input, strpos($input, '.') + 1);
       
   270             if ($options['precision'] === null) {
       
   271                 $options['precision'] = strlen($pre);
       
   272             }
       
   273 
       
   274             if (strlen($pre) >= $options['precision']) {
       
   275                 $input = substr($input, 0, strlen($input) - strlen($pre) + $options['precision']);
       
   276             }
       
   277 
       
   278             if (($options['precision'] == 0) && ($input[strlen($input) - 1] == '.')) {
       
   279                 $input = substr($input, 0, -1);
       
   280             }
       
   281         }
       
   282 
       
   283         return $input;
       
   284     }
       
   285 
       
   286     /**
       
   287      * Returns a locale formatted number depending on the given options.
       
   288      * The seperation and fraction sign is used from the set locale.
       
   289      * ##0.#  -> 12345.12345 -> 12345.12345
       
   290      * ##0.00 -> 12345.12345 -> 12345.12
       
   291      * ##,##0.00 -> 12345.12345 -> 12,345.12
       
   292      *
       
   293      * @param   string  $input    Localized number string
       
   294      * @param   array   $options  Options: number_format, locale, precision. See {@link setOptions()} for details.
       
   295      * @return  string  locale formatted number
       
   296      * @throws Zend_Locale_Exception
       
   297      */
       
   298     public static function toNumber($value, array $options = array())
       
   299     {
       
   300         // load class within method for speed
       
   301         require_once 'Zend/Locale/Math.php';
       
   302 
       
   303         $value             = Zend_Locale_Math::normalize($value);
       
   304         $value             = Zend_Locale_Math::floatalize($value);
       
   305         $options           = self::_checkOptions($options) + self::$_options;
       
   306         $options['locale'] = (string) $options['locale'];
       
   307 
       
   308         // Get correct signs for this locale
       
   309         $symbols = Zend_Locale_Data::getList($options['locale'], 'symbols');
       
   310         $oenc = iconv_get_encoding('internal_encoding');
       
   311         iconv_set_encoding('internal_encoding', 'UTF-8');
       
   312 
       
   313         // Get format
       
   314         $format = $options['number_format'];
       
   315         if ($format === null) {
       
   316             $format  = Zend_Locale_Data::getContent($options['locale'], 'decimalnumber');
       
   317             $format  = self::_seperateFormat($format, $value, $options['precision']);
       
   318 
       
   319             if ($options['precision'] !== null) {
       
   320                 $value   = Zend_Locale_Math::normalize(Zend_Locale_Math::round($value, $options['precision']));
       
   321             }
       
   322         } else {
       
   323             // seperate negative format pattern when available
       
   324             $format  = self::_seperateFormat($format, $value, $options['precision']);
       
   325             if (strpos($format, '.')) {
       
   326                 if (is_numeric($options['precision'])) {
       
   327                     $value = Zend_Locale_Math::round($value, $options['precision']);
       
   328                 } else {
       
   329                     if (substr($format, iconv_strpos($format, '.') + 1, 3) == '###') {
       
   330                         $options['precision'] = null;
       
   331                     } else {
       
   332                         $options['precision'] = iconv_strlen(iconv_substr($format, iconv_strpos($format, '.') + 1,
       
   333                                                              iconv_strrpos($format, '0') - iconv_strpos($format, '.')));
       
   334                         $format = iconv_substr($format, 0, iconv_strpos($format, '.') + 1) . '###'
       
   335                                 . iconv_substr($format, iconv_strrpos($format, '0') + 1);
       
   336                     }
       
   337                 }
       
   338             } else {
       
   339                 $value = Zend_Locale_Math::round($value, 0);
       
   340                 $options['precision'] = 0;
       
   341             }
       
   342             $value = Zend_Locale_Math::normalize($value);
       
   343         }
       
   344 
       
   345         if (iconv_strpos($format, '0') === false) {
       
   346             iconv_set_encoding('internal_encoding', $oenc);
       
   347             require_once 'Zend/Locale/Exception.php';
       
   348             throw new Zend_Locale_Exception('Wrong format... missing 0');
       
   349         }
       
   350 
       
   351         // get number parts
       
   352         $pos = iconv_strpos($value, '.');
       
   353         if ($pos !== false) {
       
   354             if ($options['precision'] === null) {
       
   355                 $precstr = iconv_substr($value, $pos + 1);
       
   356             } else {
       
   357                 $precstr = iconv_substr($value, $pos + 1, $options['precision']);
       
   358                 if (iconv_strlen($precstr) < $options['precision']) {
       
   359                     $precstr = $precstr . str_pad("0", ($options['precision'] - iconv_strlen($precstr)), "0");
       
   360                 }
       
   361             }
       
   362         } else {
       
   363             if ($options['precision'] > 0) {
       
   364                 $precstr = str_pad("0", ($options['precision']), "0");
       
   365             }
       
   366         }
       
   367 
       
   368         if ($options['precision'] === null) {
       
   369             if (isset($precstr)) {
       
   370                 $options['precision'] = iconv_strlen($precstr);
       
   371             } else {
       
   372                 $options['precision'] = 0;
       
   373             }
       
   374         }
       
   375 
       
   376         // get fraction and format lengths
       
   377         if (strpos($value, '.') !== false) {
       
   378             $number = substr((string) $value, 0, strpos($value, '.'));
       
   379         } else {
       
   380             $number = $value;
       
   381         }
       
   382 
       
   383         $prec = call_user_func(Zend_Locale_Math::$sub, $value, $number, $options['precision']);
       
   384         $prec = Zend_Locale_Math::floatalize($prec);
       
   385         $prec = Zend_Locale_Math::normalize($prec);
       
   386         if (iconv_strpos($prec, '-') !== false) {
       
   387             $prec = iconv_substr($prec, 1);
       
   388         }
       
   389 
       
   390         if (($prec == 0) and ($options['precision'] > 0)) {
       
   391             $prec = "0.0";
       
   392         }
       
   393 
       
   394         if (($options['precision'] + 2) > iconv_strlen($prec)) {
       
   395             $prec = str_pad((string) $prec, $options['precision'] + 2, "0", STR_PAD_RIGHT);
       
   396         }
       
   397 
       
   398         if (iconv_strpos($number, '-') !== false) {
       
   399             $number = iconv_substr($number, 1);
       
   400         }
       
   401         $group  = iconv_strrpos($format, ',');
       
   402         $group2 = iconv_strpos ($format, ',');
       
   403         $point  = iconv_strpos ($format, '0');
       
   404         // Add fraction
       
   405         $rest = "";
       
   406         if (iconv_strpos($format, '.')) {
       
   407             $rest   = iconv_substr($format, iconv_strpos($format, '.') + 1);
       
   408             $length = iconv_strlen($rest);
       
   409             for($x = 0; $x < $length; ++$x) {
       
   410                 if (($rest[0] == '0') || ($rest[0] == '#')) {
       
   411                     $rest = iconv_substr($rest, 1);
       
   412                 }
       
   413             }
       
   414             $format = iconv_substr($format, 0, iconv_strlen($format) - iconv_strlen($rest));
       
   415         }
       
   416 
       
   417         if ($options['precision'] == '0') {
       
   418             if (iconv_strrpos($format, '-') != 0) {
       
   419                 $format = iconv_substr($format, 0, $point)
       
   420                         . iconv_substr($format, iconv_strrpos($format, '#') + 2);
       
   421             } else {
       
   422                 $format = iconv_substr($format, 0, $point);
       
   423             }
       
   424         } else {
       
   425             $format = iconv_substr($format, 0, $point) . $symbols['decimal']
       
   426                                . iconv_substr($prec, 2);
       
   427         }
       
   428 
       
   429         $format .= $rest;
       
   430         // Add seperation
       
   431         if ($group == 0) {
       
   432             // no seperation
       
   433             $format = $number . iconv_substr($format, $point);
       
   434         } else if ($group == $group2) {
       
   435             // only 1 seperation
       
   436             $seperation = ($point - $group);
       
   437             for ($x = iconv_strlen($number); $x > $seperation; $x -= $seperation) {
       
   438                 if (iconv_substr($number, 0, $x - $seperation) !== "") {
       
   439                     $number = iconv_substr($number, 0, $x - $seperation) . $symbols['group']
       
   440                             . iconv_substr($number, $x - $seperation);
       
   441                 }
       
   442             }
       
   443             $format = iconv_substr($format, 0, iconv_strpos($format, '#')) . $number . iconv_substr($format, $point);
       
   444         } else {
       
   445 
       
   446             // 2 seperations
       
   447             if (iconv_strlen($number) > ($point - $group)) {
       
   448                 $seperation = ($point - $group);
       
   449                 $number = iconv_substr($number, 0, iconv_strlen($number) - $seperation) . $symbols['group']
       
   450                         . iconv_substr($number, iconv_strlen($number) - $seperation);
       
   451 
       
   452                 if ((iconv_strlen($number) - 1) > ($point - $group + 1)) {
       
   453                     $seperation2 = ($group - $group2 - 1);
       
   454                     for ($x = iconv_strlen($number) - $seperation2 - 2; $x > $seperation2; $x -= $seperation2) {
       
   455                         $number = iconv_substr($number, 0, $x - $seperation2) . $symbols['group']
       
   456                                 . iconv_substr($number, $x - $seperation2);
       
   457                     }
       
   458                 }
       
   459 
       
   460             }
       
   461             $format = iconv_substr($format, 0, iconv_strpos($format, '#')) . $number . iconv_substr($format, $point);
       
   462         }
       
   463         // set negative sign
       
   464         if (call_user_func(Zend_Locale_Math::$comp, $value, 0, $options['precision']) < 0) {
       
   465             if (iconv_strpos($format, '-') === false) {
       
   466                 $format = $symbols['minus'] . $format;
       
   467             } else {
       
   468                 $format = str_replace('-', $symbols['minus'], $format);
       
   469             }
       
   470         }
       
   471 
       
   472         iconv_set_encoding('internal_encoding', $oenc);
       
   473         return (string) $format;
       
   474     }
       
   475 
       
   476     private static function _seperateFormat($format, $value, $precision)
       
   477     {
       
   478         if (iconv_strpos($format, ';') !== false) {
       
   479             if (call_user_func(Zend_Locale_Math::$comp, $value, 0, $precision) < 0) {
       
   480                 $tmpformat = iconv_substr($format, iconv_strpos($format, ';') + 1);
       
   481                 if ($tmpformat[0] == '(') {
       
   482                     $format = iconv_substr($format, 0, iconv_strpos($format, ';'));
       
   483                 } else {
       
   484                     $format = $tmpformat;
       
   485                 }
       
   486             } else {
       
   487                 $format = iconv_substr($format, 0, iconv_strpos($format, ';'));
       
   488             }
       
   489         }
       
   490 
       
   491         return $format;
       
   492     }
       
   493 
       
   494 
       
   495     /**
       
   496      * Checks if the input contains a normalized or localized number
       
   497      *
       
   498      * @param   string  $input    Localized number string
       
   499      * @param   array   $options  Options: locale. See {@link setOptions()} for details.
       
   500      * @return  boolean           Returns true if a number was found
       
   501      */
       
   502     public static function isNumber($input, array $options = array())
       
   503     {
       
   504         if (!self::_getUniCodeSupport()) {
       
   505             trigger_error("Sorry, your PCRE extension does not support UTF8 which is needed for the I18N core", E_USER_NOTICE);
       
   506         }
       
   507 
       
   508         $options = self::_checkOptions($options) + self::$_options;
       
   509 
       
   510         // Get correct signs for this locale
       
   511         $symbols = Zend_Locale_Data::getList($options['locale'],'symbols');
       
   512 
       
   513         $regexs = Zend_Locale_Format::_getRegexForType('decimalnumber', $options);
       
   514         $regexs = array_merge($regexs, Zend_Locale_Format::_getRegexForType('scientificnumber', $options));
       
   515         if (!empty($input) && ($input[0] == $symbols['decimal'])) {
       
   516             $input = 0 . $input;
       
   517         }
       
   518         foreach ($regexs as $regex) {
       
   519             preg_match($regex, $input, $found);
       
   520             if (isset($found[0])) {
       
   521                 return true;
       
   522             }
       
   523         }
       
   524 
       
   525         return false;
       
   526     }
       
   527 
       
   528     /**
       
   529      * Internal method to convert cldr number syntax into regex
       
   530      *
       
   531      * @param  string $type
       
   532      * @return string
       
   533      */
       
   534     private static function _getRegexForType($type, $options)
       
   535     {
       
   536         $decimal  = Zend_Locale_Data::getContent($options['locale'], $type);
       
   537         $decimal  = preg_replace('/[^#0,;\.\-Ee]/u', '',$decimal);
       
   538         $patterns = explode(';', $decimal);
       
   539 
       
   540         if (count($patterns) == 1) {
       
   541             $patterns[1] = '-' . $patterns[0];
       
   542         }
       
   543 
       
   544         $symbols = Zend_Locale_Data::getList($options['locale'],'symbols');
       
   545 
       
   546         foreach($patterns as $pkey => $pattern) {
       
   547             $regex[$pkey]  = '/^';
       
   548             $rest   = 0;
       
   549             $end    = null;
       
   550             if (strpos($pattern, '.') !== false) {
       
   551                 $end     = substr($pattern, strpos($pattern, '.') + 1);
       
   552                 $pattern = substr($pattern, 0, -strlen($end) - 1);
       
   553             }
       
   554 
       
   555             if (strpos($pattern, ',') !== false) {
       
   556                 $parts = explode(',', $pattern);
       
   557                 $count = count($parts);
       
   558                 foreach($parts as $key => $part) {
       
   559                     switch ($part) {
       
   560                         case '#':
       
   561                         case '-#':
       
   562                             if ($part[0] == '-') {
       
   563                                 $regex[$pkey] .= '[' . $symbols['minus'] . '-]{0,1}';
       
   564                             } else {
       
   565                                 $regex[$pkey] .= '[' . $symbols['plus'] . '+]{0,1}';
       
   566                             }
       
   567 
       
   568                             if (($parts[$key + 1]) == '##0')  {
       
   569                                 $regex[$pkey] .= '[0-9]{1,3}';
       
   570                             } else if (($parts[$key + 1]) == '##') {
       
   571                                 $regex[$pkey] .= '[0-9]{1,2}';
       
   572                             } else {
       
   573                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 1):"' . $pattern . '"');
       
   574                             }
       
   575                             break;
       
   576                         case '##':
       
   577                             if ($parts[$key + 1] == '##0') {
       
   578                                 $regex[$pkey] .=  '(\\' . $symbols['group'] . '{0,1}[0-9]{2})*';
       
   579                             } else {
       
   580                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 2):"' . $pattern . '"');
       
   581                             }
       
   582                             break;
       
   583                         case '##0':
       
   584                             if ($parts[$key - 1] == '##') {
       
   585                                 $regex[$pkey] .= '[0-9]';
       
   586                             } else if (($parts[$key - 1] == '#') || ($parts[$key - 1] == '-#')) {
       
   587                                 $regex[$pkey] .= '(\\' . $symbols['group'] . '{0,1}[0-9]{3})*';
       
   588                             } else {
       
   589                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 3):"' . $pattern . '"');
       
   590                             }
       
   591                             break;
       
   592                         case '#0':
       
   593                             if ($key == 0) {
       
   594                                 $regex[$pkey] .= '[0-9]*';
       
   595                             } else {
       
   596                                 throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 4):"' . $pattern . '"');
       
   597                             }
       
   598                             break;
       
   599                     }
       
   600                 }
       
   601             }
       
   602 
       
   603             if (strpos($pattern, 'E') !== false) {
       
   604                 if (($pattern == '#E0') || ($pattern == '#E00')) {
       
   605                     $regex[$pkey] .= '[' . $symbols['plus']. '+]{0,1}[0-9]{1,}(\\' . $symbols['decimal'] . '[0-9]{1,})*[eE][' . $symbols['plus']. '+]{0,1}[0-9]{1,}';
       
   606                 } else if (($pattern == '-#E0') || ($pattern == '-#E00')) {
       
   607                     $regex[$pkey] .= '[' . $symbols['minus']. '-]{0,1}[0-9]{1,}(\\' . $symbols['decimal'] . '[0-9]{1,})*[eE][' . $symbols['minus']. '-]{0,1}[0-9]{1,}';
       
   608                 } else {
       
   609                     throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 5):"' . $pattern . '"');
       
   610                 }
       
   611             }
       
   612 
       
   613             if (!empty($end)) {
       
   614                 if ($end == '###') {
       
   615                     $regex[$pkey] .= '(\\' . $symbols['decimal'] . '{1}[0-9]{1,}){0,1}';
       
   616                 } else if ($end == '###-') {
       
   617                     $regex[$pkey] .= '(\\' . $symbols['decimal'] . '{1}[0-9]{1,}){0,1}[' . $symbols['minus']. '-]';
       
   618                 } else {
       
   619                     throw new Zend_Locale_Exception('Unsupported token for numberformat (Pos 6):"' . $pattern . '"');
       
   620                 }
       
   621             }
       
   622 
       
   623             $regex[$pkey] .= '$/u';
       
   624         }
       
   625 
       
   626         return $regex;
       
   627     }
       
   628 
       
   629     /**
       
   630      * Alias for getNumber
       
   631      *
       
   632      * @param   string  $value    Number to localize
       
   633      * @param   array   $options  Options: locale, precision. See {@link setOptions()} for details.
       
   634      * @return  float
       
   635      */
       
   636     public static function getFloat($input, array $options = array())
       
   637     {
       
   638         return floatval(self::getNumber($input, $options));
       
   639     }
       
   640 
       
   641     /**
       
   642      * Returns a locale formatted integer number
       
   643      * Alias for toNumber()
       
   644      *
       
   645      * @param   string  $value    Number to normalize
       
   646      * @param   array   $options  Options: locale, precision. See {@link setOptions()} for details.
       
   647      * @return  string  Locale formatted number
       
   648      */
       
   649     public static function toFloat($value, array $options = array())
       
   650     {
       
   651         $options['number_format'] = Zend_Locale_Format::STANDARD;
       
   652         return self::toNumber($value, $options);
       
   653     }
       
   654 
       
   655     /**
       
   656      * Returns if a float was found
       
   657      * Alias for isNumber()
       
   658      *
       
   659      * @param   string  $input    Localized number string
       
   660      * @param   array   $options  Options: locale. See {@link setOptions()} for details.
       
   661      * @return  boolean           Returns true if a number was found
       
   662      */
       
   663     public static function isFloat($value, array $options = array())
       
   664     {
       
   665         return self::isNumber($value, $options);
       
   666     }
       
   667 
       
   668     /**
       
   669      * Returns the first found integer from an string
       
   670      * Parsing depends on given locale (grouping and decimal)
       
   671      *
       
   672      * Examples for input:
       
   673      * '  2345.4356,1234' = 23455456
       
   674      * '+23,3452.123' = 233452
       
   675      * ' 12343 ' = 12343
       
   676      * '-9456km' = -9456
       
   677      * '0' = 0
       
   678      * '(-){0,1}(\d+(\.){0,1})*(\,){0,1})\d+'
       
   679      *
       
   680      * @param   string   $input    Input string to parse for numbers
       
   681      * @param   array    $options  Options: locale. See {@link setOptions()} for details.
       
   682      * @return  integer            Returns the extracted number
       
   683      */
       
   684     public static function getInteger($input, array $options = array())
       
   685     {
       
   686         $options['precision'] = 0;
       
   687         return intval(self::getFloat($input, $options));
       
   688     }
       
   689 
       
   690     /**
       
   691      * Returns a localized number
       
   692      *
       
   693      * @param   string  $value    Number to normalize
       
   694      * @param   array   $options  Options: locale. See {@link setOptions()} for details.
       
   695      * @return  string            Locale formatted number
       
   696      */
       
   697     public static function toInteger($value, array $options = array())
       
   698     {
       
   699         $options['precision'] = 0;
       
   700         $options['number_format'] = Zend_Locale_Format::STANDARD;
       
   701         return self::toNumber($value, $options);
       
   702     }
       
   703 
       
   704     /**
       
   705      * Returns if a integer was found
       
   706      *
       
   707      * @param   string  $input    Localized number string
       
   708      * @param   array   $options  Options: locale. See {@link setOptions()} for details.
       
   709      * @return  boolean           Returns true if a integer was found
       
   710      */
       
   711     public static function isInteger($value, array $options = array())
       
   712     {
       
   713         if (!self::isNumber($value, $options)) {
       
   714             return false;
       
   715         }
       
   716 
       
   717         if (self::getInteger($value, $options) == self::getFloat($value, $options)) {
       
   718             return true;
       
   719         }
       
   720 
       
   721         return false;
       
   722     }
       
   723 
       
   724     /**
       
   725      * Converts a format string from PHP's date format to ISO format
       
   726      * Remember that Zend Date always returns localized string, so a month name which returns the english
       
   727      * month in php's date() will return the translated month name with this function... use 'en' as locale
       
   728      * if you are in need of the original english names
       
   729      *
       
   730      * The conversion has the following restrictions:
       
   731      * 'a', 'A' - Meridiem is not explicit upper/lowercase, you have to upper/lowercase the translated value yourself
       
   732      *
       
   733      * @param  string  $format  Format string in PHP's date format
       
   734      * @return string           Format string in ISO format
       
   735      */
       
   736     public static function convertPhpToIsoFormat($format)
       
   737     {
       
   738         if ($format === null) {
       
   739             return null;
       
   740         }
       
   741 
       
   742         $convert = array('d' => 'dd'  , 'D' => 'EE'  , 'j' => 'd'   , 'l' => 'EEEE', 'N' => 'eee' , 'S' => 'SS'  ,
       
   743                          'w' => 'e'   , 'z' => 'D'   , 'W' => 'ww'  , 'F' => 'MMMM', 'm' => 'MM'  , 'M' => 'MMM' ,
       
   744                          'n' => 'M'   , 't' => 'ddd' , 'L' => 'l'   , 'o' => 'YYYY', 'Y' => 'yyyy', 'y' => 'yy'  ,
       
   745                          'a' => 'a'   , 'A' => 'a'   , 'B' => 'B'   , 'g' => 'h'   , 'G' => 'H'   , 'h' => 'hh'  ,
       
   746                          'H' => 'HH'  , 'i' => 'mm'  , 's' => 'ss'  , 'e' => 'zzzz', 'I' => 'I'   , 'O' => 'Z'   ,
       
   747                          'P' => 'ZZZZ', 'T' => 'z'   , 'Z' => 'X'   , 'c' => 'yyyy-MM-ddTHH:mm:ssZZZZ',
       
   748                          'r' => 'r'   , 'U' => 'U');
       
   749         $values = str_split($format);
       
   750         foreach ($values as $key => $value) {
       
   751             if (isset($convert[$value]) === true) {
       
   752                 $values[$key] = $convert[$value];
       
   753             }
       
   754         }
       
   755 
       
   756         return join($values);
       
   757     }
       
   758 
       
   759     /**
       
   760      * Parse date and split in named array fields
       
   761      *
       
   762      * @param   string  $date     Date string to parse
       
   763      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
       
   764      * @return  array             Possible array members: day, month, year, hour, minute, second, fixed, format
       
   765      */
       
   766     private static function _parseDate($date, $options)
       
   767     {
       
   768         if (!self::_getUniCodeSupport()) {
       
   769             trigger_error("Sorry, your PCRE extension does not support UTF8 which is needed for the I18N core", E_USER_NOTICE);
       
   770         }
       
   771 
       
   772         $options = self::_checkOptions($options) + self::$_options;
       
   773         $test = array('h', 'H', 'm', 's', 'y', 'Y', 'M', 'd', 'D', 'E', 'S', 'l', 'B', 'I',
       
   774                        'X', 'r', 'U', 'G', 'w', 'e', 'a', 'A', 'Z', 'z', 'v');
       
   775 
       
   776         $format = $options['date_format'];
       
   777         $number = $date; // working copy
       
   778         $result['date_format'] = $format; // save the format used to normalize $number (convenience)
       
   779         $result['locale'] = $options['locale']; // save the locale used to normalize $number (convenience)
       
   780 
       
   781         $oenc = iconv_get_encoding('internal_encoding');
       
   782         iconv_set_encoding('internal_encoding', 'UTF-8');
       
   783         $day   = iconv_strpos($format, 'd');
       
   784         $month = iconv_strpos($format, 'M');
       
   785         $year  = iconv_strpos($format, 'y');
       
   786         $hour  = iconv_strpos($format, 'H');
       
   787         $min   = iconv_strpos($format, 'm');
       
   788         $sec   = iconv_strpos($format, 's');
       
   789         $am    = null;
       
   790         if ($hour === false) {
       
   791             $hour = iconv_strpos($format, 'h');
       
   792         }
       
   793         if ($year === false) {
       
   794             $year = iconv_strpos($format, 'Y');
       
   795         }
       
   796         if ($day === false) {
       
   797             $day = iconv_strpos($format, 'E');
       
   798             if ($day === false) {
       
   799                 $day = iconv_strpos($format, 'D');
       
   800             }
       
   801         }
       
   802 
       
   803         if ($day !== false) {
       
   804             $parse[$day]   = 'd';
       
   805             if (!empty($options['locale']) && ($options['locale'] !== 'root') &&
       
   806                 (!is_object($options['locale']) || ((string) $options['locale'] !== 'root'))) {
       
   807                 // erase day string
       
   808                     $daylist = Zend_Locale_Data::getList($options['locale'], 'day');
       
   809                 foreach($daylist as $key => $name) {
       
   810                     if (iconv_strpos($number, $name) !== false) {
       
   811                         $number = str_replace($name, "EEEE", $number);
       
   812                         break;
       
   813                     }
       
   814                 }
       
   815             }
       
   816         }
       
   817         $position = false;
       
   818 
       
   819         if ($month !== false) {
       
   820             $parse[$month] = 'M';
       
   821             if (!empty($options['locale']) && ($options['locale'] !== 'root') &&
       
   822                 (!is_object($options['locale']) || ((string) $options['locale'] !== 'root'))) {
       
   823                     // prepare to convert month name to their numeric equivalents, if requested,
       
   824                     // and we have a $options['locale']
       
   825                     $position = self::_replaceMonth($number, Zend_Locale_Data::getList($options['locale'],
       
   826                         'month'));
       
   827                 if ($position === false) {
       
   828                     $position = self::_replaceMonth($number, Zend_Locale_Data::getList($options['locale'],
       
   829                         'month', array('gregorian', 'format', 'abbreviated')));
       
   830                 }
       
   831             }
       
   832         }
       
   833         if ($year !== false) {
       
   834             $parse[$year]  = 'y';
       
   835         }
       
   836         if ($hour !== false) {
       
   837             $parse[$hour] = 'H';
       
   838         }
       
   839         if ($min !== false) {
       
   840             $parse[$min] = 'm';
       
   841         }
       
   842         if ($sec !== false) {
       
   843             $parse[$sec] = 's';
       
   844         }
       
   845 
       
   846         if (empty($parse)) {
       
   847             iconv_set_encoding('internal_encoding', $oenc);
       
   848             require_once 'Zend/Locale/Exception.php';
       
   849             throw new Zend_Locale_Exception("Unknown date format, neither date nor time in '" . $format . "' found");
       
   850         }
       
   851         ksort($parse);
       
   852 
       
   853         // get daytime
       
   854         if (iconv_strpos($format, 'a') !== false) {
       
   855             if (iconv_strpos(strtoupper($number), strtoupper(Zend_Locale_Data::getContent($options['locale'], 'am'))) !== false) {
       
   856                 $am = true;
       
   857             } else if (iconv_strpos(strtoupper($number), strtoupper(Zend_Locale_Data::getContent($options['locale'], 'pm'))) !== false) {
       
   858                 $am = false;
       
   859             }
       
   860         }
       
   861 
       
   862         // split number parts
       
   863         $split = false;
       
   864         preg_match_all('/\d+/u', $number, $splitted);
       
   865 
       
   866         if (count($splitted[0]) == 0) {
       
   867             iconv_set_encoding('internal_encoding', $oenc);
       
   868             require_once 'Zend/Locale/Exception.php';
       
   869             throw new Zend_Locale_Exception("No date part in '$date' found.");
       
   870         }
       
   871         if (count($splitted[0]) == 1) {
       
   872             $split = 0;
       
   873         }
       
   874         $cnt = 0;
       
   875         foreach($parse as $key => $value) {
       
   876 
       
   877             switch($value) {
       
   878                 case 'd':
       
   879                     if ($split === false) {
       
   880                         if (count($splitted[0]) > $cnt) {
       
   881                             $result['day']    = $splitted[0][$cnt];
       
   882                         }
       
   883                     } else {
       
   884                         $result['day'] = iconv_substr($splitted[0][0], $split, 2);
       
   885                         $split += 2;
       
   886                     }
       
   887                     ++$cnt;
       
   888                     break;
       
   889                 case 'M':
       
   890                     if ($split === false) {
       
   891                         if (count($splitted[0]) > $cnt) {
       
   892                             $result['month']  = $splitted[0][$cnt];
       
   893                         }
       
   894                     } else {
       
   895                         $result['month'] = iconv_substr($splitted[0][0], $split, 2);
       
   896                         $split += 2;
       
   897                     }
       
   898                     ++$cnt;
       
   899                     break;
       
   900                 case 'y':
       
   901                     $length = 2;
       
   902                     if ((iconv_substr($format, $year, 4) == 'yyyy')
       
   903                      || (iconv_substr($format, $year, 4) == 'YYYY')) {
       
   904                         $length = 4;
       
   905                     }
       
   906 
       
   907                     if ($split === false) {
       
   908                         if (count($splitted[0]) > $cnt) {
       
   909                             $result['year']   = $splitted[0][$cnt];
       
   910                         }
       
   911                     } else {
       
   912                         $result['year']   = iconv_substr($splitted[0][0], $split, $length);
       
   913                         $split += $length;
       
   914                     }
       
   915 
       
   916                     ++$cnt;
       
   917                     break;
       
   918                 case 'H':
       
   919                     if ($split === false) {
       
   920                         if (count($splitted[0]) > $cnt) {
       
   921                             $result['hour']   = $splitted[0][$cnt];
       
   922                         }
       
   923                     } else {
       
   924                         $result['hour']   = iconv_substr($splitted[0][0], $split, 2);
       
   925                         $split += 2;
       
   926                     }
       
   927                     ++$cnt;
       
   928                     break;
       
   929                 case 'm':
       
   930                     if ($split === false) {
       
   931                         if (count($splitted[0]) > $cnt) {
       
   932                             $result['minute'] = $splitted[0][$cnt];
       
   933                         }
       
   934                     } else {
       
   935                         $result['minute'] = iconv_substr($splitted[0][0], $split, 2);
       
   936                         $split += 2;
       
   937                     }
       
   938                     ++$cnt;
       
   939                     break;
       
   940                 case 's':
       
   941                     if ($split === false) {
       
   942                         if (count($splitted[0]) > $cnt) {
       
   943                             $result['second'] = $splitted[0][$cnt];
       
   944                         }
       
   945                     } else {
       
   946                         $result['second'] = iconv_substr($splitted[0][0], $split, 2);
       
   947                         $split += 2;
       
   948                     }
       
   949                     ++$cnt;
       
   950                     break;
       
   951             }
       
   952         }
       
   953 
       
   954         // AM/PM correction
       
   955         if ($hour !== false) {
       
   956             if (($am === true) and ($result['hour'] == 12)){
       
   957                 $result['hour'] = 0;
       
   958             } else if (($am === false) and ($result['hour'] != 12)) {
       
   959                 $result['hour'] += 12;
       
   960             }
       
   961         }
       
   962 
       
   963         if ($options['fix_date'] === true) {
       
   964             $result['fixed'] = 0; // nothing has been "fixed" by swapping date parts around (yet)
       
   965         }
       
   966 
       
   967         if ($day !== false) {
       
   968             // fix false month
       
   969             if (isset($result['day']) and isset($result['month'])) {
       
   970                 if (($position !== false) and ((iconv_strpos($date, $result['day']) === false) or
       
   971                                                (isset($result['year']) and (iconv_strpos($date, $result['year']) === false)))) {
       
   972                     if ($options['fix_date'] !== true) {
       
   973                         iconv_set_encoding('internal_encoding', $oenc);
       
   974                         require_once 'Zend/Locale/Exception.php';
       
   975                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '" . $format
       
   976                             . "' (false month, $position, $month)");
       
   977                     }
       
   978                     $temp = $result['day'];
       
   979                     $result['day']   = $result['month'];
       
   980                     $result['month'] = $temp;
       
   981                     $result['fixed'] = 1;
       
   982                 }
       
   983             }
       
   984 
       
   985             // fix switched values d <> y
       
   986             if (isset($result['day']) and isset($result['year'])) {
       
   987                 if ($result['day'] > 31) {
       
   988                     if ($options['fix_date'] !== true) {
       
   989                         iconv_set_encoding('internal_encoding', $oenc);
       
   990                         require_once 'Zend/Locale/Exception.php';
       
   991                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '"
       
   992                                                       . $format . "' (d <> y)");
       
   993                     }
       
   994                     $temp = $result['year'];
       
   995                     $result['year'] = $result['day'];
       
   996                     $result['day']  = $temp;
       
   997                     $result['fixed'] = 2;
       
   998                 }
       
   999             }
       
  1000 
       
  1001             // fix switched values M <> y
       
  1002             if (isset($result['month']) and isset($result['year'])) {
       
  1003                 if ($result['month'] > 31) {
       
  1004                     if ($options['fix_date'] !== true) {
       
  1005                         iconv_set_encoding('internal_encoding', $oenc);
       
  1006                         require_once 'Zend/Locale/Exception.php';
       
  1007                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '"
       
  1008                                                       . $format . "' (M <> y)");
       
  1009                     }
       
  1010                     $temp = $result['year'];
       
  1011                     $result['year']  = $result['month'];
       
  1012                     $result['month'] = $temp;
       
  1013                     $result['fixed'] = 3;
       
  1014                 }
       
  1015             }
       
  1016 
       
  1017             // fix switched values M <> d
       
  1018             if (isset($result['month']) and isset($result['day'])) {
       
  1019                 if ($result['month'] > 12) {
       
  1020                     if ($options['fix_date'] !== true || $result['month'] > 31) {
       
  1021                         iconv_set_encoding('internal_encoding', $oenc);
       
  1022                         require_once 'Zend/Locale/Exception.php';
       
  1023                         throw new Zend_Locale_Exception("Unable to parse date '$date' using '"
       
  1024                                                       . $format . "' (M <> d)");
       
  1025                     }
       
  1026                     $temp = $result['day'];
       
  1027                     $result['day']   = $result['month'];
       
  1028                     $result['month'] = $temp;
       
  1029                     $result['fixed'] = 4;
       
  1030                 }
       
  1031             }
       
  1032         }
       
  1033 
       
  1034         if (isset($result['year'])) {
       
  1035             if (((iconv_strlen($result['year']) == 2) && ($result['year'] < 10)) ||
       
  1036                 (((iconv_strpos($format, 'yy') !== false) && (iconv_strpos($format, 'yyyy') === false)) ||
       
  1037                 ((iconv_strpos($format, 'YY') !== false) && (iconv_strpos($format, 'YYYY') === false)))) {
       
  1038                 if (($result['year'] >= 0) && ($result['year'] < 100)) {
       
  1039                     if ($result['year'] < 70) {
       
  1040                         $result['year'] = (int) $result['year'] + 100;
       
  1041                     }
       
  1042 
       
  1043                     $result['year'] = (int) $result['year'] + 1900;
       
  1044                 }
       
  1045             }
       
  1046         }
       
  1047 
       
  1048         iconv_set_encoding('internal_encoding', $oenc);
       
  1049         return $result;
       
  1050     }
       
  1051 
       
  1052     /**
       
  1053      * Search $number for a month name found in $monthlist, and replace if found.
       
  1054      *
       
  1055      * @param  string  $number     Date string (modified)
       
  1056      * @param  array   $monthlist  List of month names
       
  1057      *
       
  1058      * @return int|false           Position of replaced string (false if nothing replaced)
       
  1059      */
       
  1060     protected static function _replaceMonth(&$number, $monthlist)
       
  1061     {
       
  1062         // If $locale was invalid, $monthlist will default to a "root" identity
       
  1063         // mapping for each month number from 1 to 12.
       
  1064         // If no $locale was given, or $locale was invalid, do not use this identity mapping to normalize.
       
  1065         // Otherwise, translate locale aware month names in $number to their numeric equivalents.
       
  1066         $position = false;
       
  1067         if ($monthlist && $monthlist[1] != 1) {
       
  1068             foreach($monthlist as $key => $name) {
       
  1069                 if (($position = iconv_strpos($number, $name, 0, 'UTF-8')) !== false) {
       
  1070                     $number   = str_ireplace($name, $key, $number);
       
  1071                     return $position;
       
  1072                 }
       
  1073             }
       
  1074         }
       
  1075 
       
  1076         return false;
       
  1077     }
       
  1078 
       
  1079     /**
       
  1080      * Returns the default date format for $locale.
       
  1081      *
       
  1082      * @param  string|Zend_Locale  $locale  OPTIONAL Locale of $number, possibly in string form (e.g. 'de_AT')
       
  1083      * @return string  format
       
  1084      * @throws Zend_Locale_Exception  throws an exception when locale data is broken
       
  1085      */
       
  1086     public static function getDateFormat($locale = null)
       
  1087     {
       
  1088         $format = Zend_Locale_Data::getContent($locale, 'date');
       
  1089         if (empty($format)) {
       
  1090             require_once 'Zend/Locale/Exception.php';
       
  1091             throw new Zend_Locale_Exception("failed to receive data from locale $locale");
       
  1092         }
       
  1093 
       
  1094         return $format;
       
  1095     }
       
  1096 
       
  1097     /**
       
  1098      * Returns an array with the normalized date from an locale date
       
  1099      * a input of 10.01.2006 without a $locale would return:
       
  1100      * array ('day' => 10, 'month' => 1, 'year' => 2006)
       
  1101      * The 'locale' option is only used to convert human readable day
       
  1102      * and month names to their numeric equivalents.
       
  1103      * The 'format' option allows specification of self-defined date formats,
       
  1104      * when not using the default format for the 'locale'.
       
  1105      *
       
  1106      * @param   string  $date     Date string
       
  1107      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
       
  1108      * @return  array             Possible array members: day, month, year, hour, minute, second, fixed, format
       
  1109      */
       
  1110     public static function getDate($date, array $options = array())
       
  1111     {
       
  1112         $options = self::_checkOptions($options) + self::$_options;
       
  1113         if (empty($options['date_format'])) {
       
  1114             $options['format_type'] = 'iso';
       
  1115             $options['date_format'] = self::getDateFormat($options['locale']);
       
  1116         }
       
  1117 
       
  1118         return self::_parseDate($date, $options);
       
  1119     }
       
  1120 
       
  1121     /**
       
  1122      * Returns if the given datestring contains all date parts from the given format.
       
  1123      * If no format is given, the default date format from the locale is used
       
  1124      * If you want to check if the date is a proper date you should use Zend_Date::isDate()
       
  1125      *
       
  1126      * @param   string  $date     Date string
       
  1127      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
       
  1128      * @return  boolean
       
  1129      */
       
  1130     public static function checkDateFormat($date, array $options = array())
       
  1131     {
       
  1132         try {
       
  1133             $date = self::getDate($date, $options);
       
  1134         } catch (Exception $e) {
       
  1135             return false;
       
  1136         }
       
  1137 
       
  1138         if (empty($options['date_format'])) {
       
  1139             $options['format_type'] = 'iso';
       
  1140             $options['date_format'] = self::getDateFormat($options['locale']);
       
  1141         }
       
  1142         $options = self::_checkOptions($options) + self::$_options;
       
  1143 
       
  1144         // day expected but not parsed
       
  1145         if ((iconv_strpos($options['date_format'], 'd', 0, 'UTF-8') !== false) and (!isset($date['day']) or ($date['day'] === ""))) {
       
  1146             return false;
       
  1147         }
       
  1148 
       
  1149         // month expected but not parsed
       
  1150         if ((iconv_strpos($options['date_format'], 'M', 0, 'UTF-8') !== false) and (!isset($date['month']) or ($date['month'] === ""))) {
       
  1151             return false;
       
  1152         }
       
  1153 
       
  1154         // year expected but not parsed
       
  1155         if (((iconv_strpos($options['date_format'], 'Y', 0, 'UTF-8') !== false) or
       
  1156              (iconv_strpos($options['date_format'], 'y', 0, 'UTF-8') !== false)) and (!isset($date['year']) or ($date['year'] === ""))) {
       
  1157             return false;
       
  1158         }
       
  1159 
       
  1160         // second expected but not parsed
       
  1161         if ((iconv_strpos($options['date_format'], 's', 0, 'UTF-8') !== false) and (!isset($date['second']) or ($date['second'] === ""))) {
       
  1162             return false;
       
  1163         }
       
  1164 
       
  1165         // minute expected but not parsed
       
  1166         if ((iconv_strpos($options['date_format'], 'm', 0, 'UTF-8') !== false) and (!isset($date['minute']) or ($date['minute'] === ""))) {
       
  1167             return false;
       
  1168         }
       
  1169 
       
  1170         // hour expected but not parsed
       
  1171         if (((iconv_strpos($options['date_format'], 'H', 0, 'UTF-8') !== false) or
       
  1172              (iconv_strpos($options['date_format'], 'h', 0, 'UTF-8') !== false)) and (!isset($date['hour']) or ($date['hour'] === ""))) {
       
  1173             return false;
       
  1174         }
       
  1175 
       
  1176         return true;
       
  1177     }
       
  1178 
       
  1179     /**
       
  1180      * Returns the default time format for $locale.
       
  1181      *
       
  1182      * @param  string|Zend_Locale  $locale  OPTIONAL Locale of $number, possibly in string form (e.g. 'de_AT')
       
  1183      * @return string  format
       
  1184      */
       
  1185     public static function getTimeFormat($locale = null)
       
  1186     {
       
  1187         $format = Zend_Locale_Data::getContent($locale, 'time');
       
  1188         if (empty($format)) {
       
  1189             require_once 'Zend/Locale/Exception.php';
       
  1190             throw new Zend_Locale_Exception("failed to receive data from locale $locale");
       
  1191         }
       
  1192         return $format;
       
  1193     }
       
  1194 
       
  1195     /**
       
  1196      * Returns an array with 'hour', 'minute', and 'second' elements extracted from $time
       
  1197      * according to the order described in $format.  For a format of 'H:m:s', and
       
  1198      * an input of 11:20:55, getTime() would return:
       
  1199      * array ('hour' => 11, 'minute' => 20, 'second' => 55)
       
  1200      * The optional $locale parameter may be used to help extract times from strings
       
  1201      * containing both a time and a day or month name.
       
  1202      *
       
  1203      * @param   string  $time     Time string
       
  1204      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
       
  1205      * @return  array             Possible array members: day, month, year, hour, minute, second, fixed, format
       
  1206      */
       
  1207     public static function getTime($time, array $options = array())
       
  1208     {
       
  1209         $options = self::_checkOptions($options) + self::$_options;
       
  1210         if (empty($options['date_format'])) {
       
  1211             $options['format_type'] = 'iso';
       
  1212             $options['date_format'] = self::getTimeFormat($options['locale']);
       
  1213         }
       
  1214         return self::_parseDate($time, $options);
       
  1215     }
       
  1216 
       
  1217     /**
       
  1218      * Returns the default datetime format for $locale.
       
  1219      *
       
  1220      * @param  string|Zend_Locale  $locale  OPTIONAL Locale of $number, possibly in string form (e.g. 'de_AT')
       
  1221      * @return string  format
       
  1222      */
       
  1223     public static function getDateTimeFormat($locale = null)
       
  1224     {
       
  1225         $format = Zend_Locale_Data::getContent($locale, 'datetime');
       
  1226         if (empty($format)) {
       
  1227             require_once 'Zend/Locale/Exception.php';
       
  1228             throw new Zend_Locale_Exception("failed to receive data from locale $locale");
       
  1229         }
       
  1230         return $format;
       
  1231     }
       
  1232 
       
  1233     /**
       
  1234      * Returns an array with 'year', 'month', 'day', 'hour', 'minute', and 'second' elements
       
  1235      * extracted from $datetime according to the order described in $format.  For a format of 'd.M.y H:m:s',
       
  1236      * and an input of 10.05.1985 11:20:55, getDateTime() would return:
       
  1237      * array ('year' => 1985, 'month' => 5, 'day' => 10, 'hour' => 11, 'minute' => 20, 'second' => 55)
       
  1238      * The optional $locale parameter may be used to help extract times from strings
       
  1239      * containing both a time and a day or month name.
       
  1240      *
       
  1241      * @param   string  $datetime DateTime string
       
  1242      * @param   array   $options  Options: format_type, fix_date, locale, date_format. See {@link setOptions()} for details.
       
  1243      * @return  array             Possible array members: day, month, year, hour, minute, second, fixed, format
       
  1244      */
       
  1245     public static function getDateTime($datetime, array $options = array())
       
  1246     {
       
  1247         $options = self::_checkOptions($options) + self::$_options;
       
  1248         if (empty($options['date_format'])) {
       
  1249             $options['format_type'] = 'iso';
       
  1250             $options['date_format'] = self::getDateTimeFormat($options['locale']);
       
  1251         }
       
  1252         return self::_parseDate($datetime, $options);
       
  1253     }
       
  1254 
       
  1255     /**
       
  1256      * Internal method to detect of Unicode supports UTF8
       
  1257      * which should be enabled within vanilla php installations
       
  1258      *
       
  1259      * @return boolean
       
  1260      */
       
  1261     protected static function _getUniCodeSupport()
       
  1262     {
       
  1263         return (@preg_match('/\pL/u', 'a')) ? true : false;
       
  1264     }
       
  1265 }