|
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 } |