Вход Регистрация
Файл: concrete5.7.5.6/concrete/vendor/punic/punic/code/Calendar.php
Строк: 2409
<?php

namespace Punic;

/*
 * Comments marked as @TZWS have been added because it seems than PHP does
 * not support timezones with seconds.
 * Furthermore: the Unicode specs (http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table) says the following:
 * "The ISO8601 basic format with hours, minutes and optional seconds fields. Note: The seconds field is not supported by the
 * ISO8601 specification."
 */

/**
 * Date and time related functions.
 */
class Calendar
{
    
/** @var array */
    
protected static $timezoneCache;
    
/** @var string[] */
    
protected static $weekdayDictionary = array('sun''mon''tue''wed''thu''fri''sat');

    
/**
     * Convert a date/time representation to a {@link http://php.net/manual/class.datetime.php DateTime} instance.
     *
     * @param number|DateTime|string $value An Unix timestamp, a `DateTime` instance DateTime or a string accepted by {@link http://php.net/manual/function.strtotime.php strtotime}.
     * @param string|DateTimeZone $toTimezone The timezone to set; leave empty to use the value of $fromTimezone (if it's empty we'll use the default timezone or the timezone associated to $value if it's already a `DateTime`).
     * @param string|DateTimeZone $fromTimezone The original timezone of $value; leave empty to use the default timezone (or the timezone associated to $value if it's already a `DateTime`).
     *
     * @return DateTime|null Returns null if $value is empty, a `DateTime` instance otherwise.
     *
     * @throws PunicExceptionBadArgumentType Throws an exception if $value is not empty and can't be converted to a `DateTime` instance or if $toTimezone is not empty and is not valid.
     *
     * @example Convert a Unix timestamp to a DateTime instance with the current time zone:
     * ```php
     * PunicCalendar::toDateTime(1409648286);
     * ```
     * @example Convert a Unix timestamp to a DateTime instance with a specific time zone:
     * ```php
     * PunicCalendar::toDateTime(1409648286, 'Europe/Rome');
     * PunicCalendar::toDateTime(1409648286, new DateTimeZone('Europe/Rome'));
     * ```
     * @example Convert a string to a DateTime instance with the current time zone:
     * ```php
     * PunicCalendar::toDateTime('2014-03-07 13:30');
     * ```
     * @example Convert a string to a DateTime instance with a specific time zone:
     * ```php
     * PunicCalendar::toDateTime('2014-03-07 13:30', 'Europe/Rome');
     * ```
     * Please remark that in this case '2014-03-07 13:30' is converted to a DateTime instance with the current timezone, and <u>after</u> we change the timezone.
     * So, if your system default timezone is 'America/Los_Angeles' (GMT -8), the resulting date/time will be '2014-03-07 22:30 GMT+1' since it'll be converted to 'Europe/Rome' (GMT +1)
     */
    
public static function toDateTime($value$toTimezone ''$fromTimezone '')
    {
        
$result null;
        if ((!empty(
$value)) || ($value === 0) || ($value === '0')) {
            
$tzFrom null;
            if (!empty(
$fromTimezone)) {
                if (
is_string($fromTimezone)) {
                    try {
                        
$tzFrom = new DateTimeZone($fromTimezone);
                    } catch (
Exception $x) {
                        throw new 
ExceptionBadArgumentType($fromTimezone'\DateTimeZone'$x);
                    }
                } elseif (
is_a($fromTimezone'DateTimeZone')) {
                    
$tzFrom $fromTimezone;
                } else {
                    throw new 
ExceptionBadArgumentType($fromTimezone'\DateTimeZone');
                }
            }
            if (
is_int($value) || is_float($value)) {
                
$result = new DateTime();
                
$result->setTimestamp($value);
                if (
$tzFrom !== null) {
                    
$result->setTimezone($tzFrom);
                }
            } elseif (
$value instanceof DateTime) {
                
$result = clone $value;
                if (
$tzFrom !== null) {
                    
$result->setTimezone($tzFrom);
                }
            } elseif (
is_string($value)) {
                if (
is_numeric($value)) {
                    
$result = new DateTime();
                    
$result->setTimestamp($value);
                    if (
$tzFrom !== null) {
                        
$result->setTimezone($tzFrom);
                    }
                } else {
                    try {
                        if (
$tzFrom === null) {
                            
$result = new DateTime($value);
                        } else {
                            
$result = new DateTime($value$tzFrom);
                        }
                    } catch (
Exception $x) {
                        throw new 
ExceptionBadArgumentType($value'\DateTime'$x);
                    }
                }
            } else {
                throw new 
ExceptionBadArgumentType($value'\DateTime');
            }
            if (
$result) {
                if (!empty(
$toTimezone)) {
                    if (
is_string($toTimezone)) {
                        try {
                            
$result->setTimezone(new DateTimeZone($toTimezone));
                        } catch (
Exception $x) {
                            throw new 
ExceptionBadArgumentType($toTimezone'\DateTimeZone'$x);
                        }
                    } elseif (
is_a($toTimezone'DateTimeZone')) {
                        
$result->setTimezone($toTimezone);
                    } else {
                        throw new 
ExceptionBadArgumentType($toTimezone'\DateTimeZone');
                    }
                }
            }
        }

        return 
$result;
    }

    
/**
     * Converts a format string from {@link http://php.net/manual/en/function.date.php#refsect1-function.date-parameters PHP's date format} to {@link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table ISO format}.
     * The following extra format chunks are introduced:
     * - 'P': ISO-8601 numeric representation of the day of the week (same as 'e' but not locale dependent)
     * - 'PP': Numeric representation of the day of the week, from 0 (for Sunday) to 6 (for Saturday)
     * - 'PPP': English ordinal suffix for the day of the month
     * - 'PPPP': The day of the year (starting from 0)
     * - 'PPPPP': Number of days in the given month
     * - 'PPPPPP': Whether it's a leap year: 1 if it is a leap year, 0 otherwise.
     * - 'PPPPPPP': Lowercase Ante meridiem and Post meridiem (English only, for other locales it's the same as 'a')
     * - 'PPPPPPPP': Swatch Internet time
     * - 'PPPPPPPPP': Microseconds
     * - 'PPPPPPPPPP': Whether or not the date is in daylight saving time    1 if Daylight Saving Time, 0 otherwise.
     * - 'PPPPPPPPPPP': Timezone offset in seconds
     * - 'PPPPPPPPPPPP': RFC 2822 formatted date (Example: 'Thu, 21 Dec 2000 16:01:07 +0200')
     * - 'PPPPPPPPPPPPP': Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
     *
     * @param string $format The PHP date/time format string to convert.
     *
     * @return string Returns the ISO date/time format corresponding to the specified PHP date/time format.
     */
    
public static function convertPhpToIsoFormat($format)
    {
        static 
$cache = array();
        static 
$convert = array(
            
'd' => 'dd',
            
'D' => 'EE',
            
'j' => 'd',
            
'l' => 'EEEE',
            
'N' => 'P',
            
'S' => 'PPP',
            
'w' => 'PP',
            
'z' => 'PPPP',
            
'W' => 'ww',
            
'F' => 'MMMM',
            
'm' => 'MM',
            
'M' => 'MMM',
            
'n' => 'M',
            
't' => 'PPPPP',
            
'L' => 'PPPPPP',
            
'o' => 'YYYY',
            
'Y' => 'yyyy',
            
'y' => 'yy',
            
'a' => 'PPPPPPP',
            
'A' => 'a',
            
'B' => 'PPPPPPPP',
            
'g' => 'h',
            
'G' => 'H',
            
'h' => 'hh',
            
'H' => 'HH',
            
'i' => 'mm',
            
's' => 'ss',
            
'e' => 'VV',
            
'I' => 'I',
            
'O' => 'Z',
            
'P' => 'ZZZZZ',
            
'T' => 'z',
            
'Z' => 'PPPPPPPPPPP',
            
'c' => 'yyyy-MM-ddTHH:mm:ssZZZZZ',
            
'r' => 'PPPPPPPPPPPP',
            
'U' => 'U',
            
'u' => 'PPPPPPPPP',
            
'I' => 'PPPPPPPPPP',
            
'U' => 'PPPPPPPPPPPPP',
        );
        if (!
is_string($format)) {
            return 
'';
        }
        if (!isset(
$cache[$format])) {
            
$escaped false;
            
$inEscapedString false;
            
$converted = array();
            foreach (
str_split($format) as $char) {
                if (!
$escaped && $char == '\') {
                    // Next char will be escaped: let'
s remember it
                    $escaped 
true;
                } elseif (
$escaped) {
                    if (!
$inEscapedString) {
                        
// First escaped string: start the quoted chunk
                        
$converted[] = "'";
                        
$inEscapedString true;
                    }
                    
// Since the previous char was a  and we are in the quoted
                    // chunk, let's simply add $char as it is
                    
$converted[] = $char;
                    
$escaped false;
                } elseif (
$char == "'") {
                    
// Single quotes need to be escaped like this
                    
$converted[] = "''";
                } else {
                    if (
$inEscapedString) {
                        
// Close the single-quoted chunk
                        
$converted[] = "'";
                        
$inEscapedString false;
                    }
                    
// Convert the unescaped char if needed
                    
if (isset($convert[$char])) {
                        
$converted[] = $convert[$char];
                    } else {
                        
$converted[] = $char;
                    }
                }
            }
            
$cache[$format] = implode($converted);
        }

        return 
$cache[$format];
    }

    
/**
     * Get the name of an era.
     *
     * @param number|DateTime $value The year number or the DateTime instance for which you want the name of the era.
     * @param string $width The format name; it can be 'wide' (eg 'Before Christ'), 'abbreviated' (eg 'BC') or 'narrow' (eg 'B').
     * @param string $locale The locale to use. If empty we'll use the default locale set with {@link PunicData::setDefaultLocale()}.
     *
     * @return string Returns an empty string if $value is empty, the name of the era otherwise.
     *
     * @throws PunicExceptionBadArgumentType Throws a BadArgumentType exception if $value is not valid.
     * @throws PunicExceptionValueNotInList Throws a ValueNotInList exception if $width is not valid.
     * @throws PunicException Throws a generic exception in case of other problems (for instance if you specify an invalid locale).
     */
    
public static function getEraName($value$width 'abbreviated'$locale '')
    {
        
$result '';
        if ((!empty(
$value)) || ($value === 0) || ($value === '0')) {
            
$year null;
            if (
is_int($value)) {
                
$year $value;
            } elseif (
is_float($value)) {
                
$year intval($value);
            } elseif (
is_string($value)) {
                if (
is_numeric($value)) {
                    
$year intval($value);
                }
            } elseif (
is_a($value'DateTime')) {
                
$year intval($value->format('Y'));
            }
            if (
$year === null) {
                throw new 
ExceptionBadArgumentType($value'year number');
            }
            
$data Data::get('calendar'$locale);
            
$data $data['eras'];
            if (!isset(
$data[$width])) {
                throw new 
ExceptionValueNotInList($widtharray_keys($data));
            }
            
$result $data[$width][($year 0) ? '0' '1'];
        }

        return 
$result;
    }

    
/**
     * Get the name of a month.
     *
     * @param number|DateTime $value The month number (1-12) or a DateTime instance for which you want the name of the month.
     * @param string $width The format name; it can be 'wide' (eg 'January'), 'abbreviated' (eg 'Jan') or 'narrow' (eg 'J').
     * @param string $locale The locale to use. If empty we'll use the default locale set with {@link PunicData::setDefaultLocale()}.
     * @param bool $standAlone Set to true to return the form used independently (such as in calendar header), set to false if the month name will be part of a date.
     *
     * @return string Returns an empty string if $value is empty, the name of the month otherwise.
     *
     * @throws PunicExceptionBadArgumentType Throws a BadArgumentType exception if $value is not valid.
     * @throws PunicExceptionValueNotInList Throws a ValueNotInList exception if $width is not valid.
     * @throws PunicException Throws a generic exception in case of other problems (for instance if you specify an invalid locale).
     */
    
public static function getMonthName($value$width 'wide'$locale ''$standAlone false)
    {
        
$result '';
        if ((!empty(
$value)) || ($value === 0) || ($value === '0')) {
            
$month null;
            if (
is_int($value)) {
                
$month $value;
            } elseif (
is_float($value)) {
                
$month intval($value);
            } elseif (
is_string($value)) {
                if (
is_numeric($value)) {
                    
$month intval($value);
                }
            } elseif (
is_a($value'DateTime')) {
                
$month intval($value->format('n'));
            }
            if ((
$month === null) || (($month 1) || ($month 12))) {
                throw new 
ExceptionBadArgumentType($value'month number');
            }
            
$data Data::get('calendar'$locale);
            
$data $data['months'][$standAlone 'stand-alone' 'format'];
            if (!isset(
$data[$width])) {
                throw new 
ExceptionValueNotInList($widtharray_keys($data));
            }
            
$result $data[$width][$month];
        }

        return 
$result;
    }

    
/**
     * Get the name of a week day.
     *
     * @param number|DateTime $value A week day number (from 0-Sunday to 6-Saturnday) or a DateTime instance for which you want the name of the day of the week.
     * @param string $width The format name; it can be 'wide' (eg 'Sunday'), 'abbreviated' (eg 'Sun'), 'short' (eg 'Su') or 'narrow' (eg 'S').
     * @param string $locale The locale to use. If empty we'll use the default locale set with {@link PunicData::setDefaultLocale()}.
     * @param bool $standAlone Set to true to return the form used independently (such as in calendar header), set to false if the week day name will be part of a date.
     *
     * @return string Returns an empty string if $value is empty, the name of the week day name otherwise.
     *
     * @throws PunicExceptionBadArgumentType Throws a BadArgumentType exception if $value is not valid.
     * @throws PunicExceptionValueNotInList Throws a ValueNotInList exception if $width is not valid.
     * @throws PunicException Throws a generic exception in case of other problems (for instance if you specify an invalid locale).
     */
    
public static function getWeekdayName($value$width 'wide'$locale ''$standAlone false)
    {
        
$result '';
        if ((!empty(
$value)) || ($value === 0) || ($value === '0')) {
            
$weekday null;
            if (
is_int($value)) {
                
$weekday $value;
            } elseif (
is_float($value)) {
                
$weekday intval($value);
            } elseif (
is_string($value)) {
                if (
is_numeric($value)) {
                    
$weekday intval($value);
                }
            } elseif (
is_a($value'DateTime')) {
                
$weekday intval($value->format('w'));
            }
            if ((
$weekday === null) || (($weekday 0) || ($weekday 6))) {
                throw new 
ExceptionBadArgumentType($value'weekday number');
            }
            
$weekday self::$weekdayDictionary[$weekday];
            
$data Data::get('calendar'$locale);
            
$data $data['days'][$standAlone 'stand-alone' 'format'];
            if (!isset(
$data[$width])) {
                throw new 
ExceptionValueNotInList($widtharray_keys($data));
            }
            
$result $data[$width][$weekday];
        }

        return 
$result;
    }

    
/**
     * Get the name of a quarter.
     *
     * @param number|DateTime $value A quarter number (from 1 to 4) or a DateTime instance for which you want the name of the day of the quarter.
     * @param string $width The format name; it can be 'wide' (eg '1st quarter'), 'abbreviated' (eg 'Q1') or 'narrow' (eg '1').
     * @param string $locale The locale to use. If empty we'll use the default locale set with {@link PunicData::setDefaultLocale()}.
     * @param bool $standAlone Set to true to return the form used independently (such as in calendar header), set to false if the quarter name will be part of a date.
     *
     * @return string Returns an empty string if $value is empty, the name of the quarter name otherwise.
     *
     * @throws PunicExceptionBadArgumentType Throws a BadArgumentType exception if $value is not valid.
     * @throws PunicExceptionValueNotInList Throws a ValueNotInList exception if $width is not valid.
     * @throws PunicException Throws a generic exception in case of other problems (for instance if you specify an invalid locale).
     */
    
public static function getQuarterName($value$width 'wide'$locale ''$standAlone false)
    {
        
$result '';
        if ((!empty(
$value)) || ($value === 0) || ($value === '0')) {
            
$quarter null;
            if (
is_int($value)) {
                
$quarter $value;
            } elseif (
is_float($value)) {
                
$quarter intval($value);
            } elseif (
is_string($value)) {
                if (
is_numeric($value)) {
                    
$quarter intval($value);
                }
            } elseif (
is_a($value'DateTime')) {
                
$quarter intval(floor((intval($value->format('n')) - 1) / 3));
            }
            if ((
$quarter === null) || (($quarter 1) || ($quarter 4))) {
                throw new 
ExceptionBadArgumentType($value'quarter number');
            }
            
$data Data::get('calendar'$locale);
            
$data $data['quarters'][$standAlone 'stand-alone' 'format'];
            if (!isset(
$data[$width])) {
                throw new 
ExceptionValueNotInList($widtharray_keys($data));
            }
            
$result $data[$width][$quarter];
        }

        return 
$result;
    }

    
/**
     * Get the name of a day period (AM/PM).
     *
     * @param number|string|DateTime $value An hour (from 0 to 23), a standard period name ('am' or 'pm', lower or upper case) a DateTime instance for which you want the name of the day period.
     * @param string $width The format name; it can be 'wide' (eg 'AM'), 'abbreviated' (eg 'AM') or 'narrow' (eg 'a').
     * @param string $locale The locale to use. If empty we'll use the default locale set with {@link PunicData::setDefaultLocale()}.
     * @param bool $standAlone Set to true to return the form used independently (such as in calendar header), set to false if the day period name will be part of a date.
     *
     * @return string Returns an empty string if $value is empty, the name of the day period name otherwise.
     *
     * @throws PunicExceptionBadArgumentType Throws a BadArgumentType exception if $value is not valid.
     * @throws PunicExceptionValueNotInList Throws a ValueNotInList exception if $width is not valid.
     * @throws PunicException Throws a generic exception in case of other problems (for instance if you specify an invalid locale).
     */
    
public static function getDayperiodName($value$width 'wide'$locale ''$standAlone false)
    {
        static 
$dictionary = array('am''pm');
        
$result '';
        if ((!empty(
$value)) || ($value === 0) || ($value === '0')) {
            
$dayperiod null;
            
$hours null;
            if (
is_int($value)) {
                
$hours $value;
            } elseif (
is_float($value)) {
                
$hours intval($value);
            } elseif (
is_string($value)) {
                if (
is_numeric($value)) {
                    
$hours intval($value);
                } else {
                    
$s strtolower($value);
                    if (
in_array($s$dictionarytrue)) {
                        
$dayperiod $s;
                    }
                }
            } elseif (
is_a($value'DateTime')) {
                
$dayperiod $value->format('a');
            }
            if ((
$hours !== null) && ($hours >= 0) && ($hours <= 23)) {
                
$dayperiod = ($hours 12) ? 'am' 'pm';
            }
            if (
$dayperiod === null) {
                throw new 
ExceptionBadArgumentType($value'day period');
            }
            
$data Data::get('calendar'$locale);
            
$data $data['dayPeriods'][$standAlone 'stand-alone' 'format'];
            if (!isset(
$data[$width])) {
                throw new 
ExceptionValueNotInList($widtharray_keys($data));
            }
            
$result $data[$width][$dayperiod];
        }

        return 
$result;
    }

    
/**
     * Returns the localized name of a timezone, no location-specific.
     *
     * @param string|DateTime|DateTimeZone $value The php name of a timezone, or a DateTime instance or a DateTimeZone instance for which you want the localized timezone name.
     * @param string $width The format name; it can be 'long' (eg 'Greenwich Mean Time') or 'short' (eg 'GMT').
     * @param string $kind Set to 'daylight' to retrieve the daylight saving time name, set to 'standard' to retrieve the standard time, set to 'generic' to retrieve the generic name, set to '' to determine automatically the dst (if $value is DateTime) or the generic (otherwise).
     * @param string $locale The locale to use. If empty we'll use the default locale set with {@link PunicData::setDefaultLocale()}.
     *
     * @return string Returns an empty string if the timezone has not been found (maybe we don't have the data in the specified $width), the timezone name otherwise.
     *
     * @throws PunicException Throws a generic exception in case of problems (for instance if you specify an invalid locale).
     */
    
public static function getTimezoneNameNoLocationSpecific($value$width 'long'$kind ''$locale '')
    {
        
$cacheKey json_encode(array($value$width$kind, empty($locale) ? Data::getDefaultLocale() : $locale));
        if (isset(
self::$timezoneCache[$cacheKey])) {
            return 
self::$timezoneCache[$cacheKey];
        }

        
$result '';
        if (!empty(
$value)) {
            
$receivedPhpName '';
            
$date '';
            if (
is_string($value)) {
                
$receivedPhpName $value;
            } elseif (
is_a($value'\DateTime')) {
                
$receivedPhpName = static::getTimezoneNameFromDatetime($value);
                
$date $value->format('Y-m-d H:i');
                if (empty(
$kind)) {
                    if (
intval($value->format('I')) === 1) {
                        
$kind 'daylight';
                    } else {
                        
$kind 'standard';
                    }
                }
            } elseif (
is_a($value'\DateTimeZone')) {
                
$receivedPhpName = static::getTimezoneNameFromTimezone($value);
            }
            if (isset(
$receivedPhpName[0])) {
                
$metazoneCode '';
                
$data Data::getGeneric('metaZones');
                
$phpNames = static::getTimezonesAliases($receivedPhpName);
                if (!isset(
$metazoneCode[0])) {
                    foreach (
$phpNames as $phpName) {
                        
$path array_merge(array('metazoneInfo'), explode('/'$phpName));
                        
$tzInfo $data;
                        foreach (
$path as $chunk) {
                            if (isset(
$tzInfo[$chunk])) {
                                
$tzInfo $tzInfo[$chunk];
                            } else {
                                
$tzInfo null;
                                break;
                            }
                        }
                        if (
is_array($tzInfo)) {
                            foreach (
$tzInfo as $tz) {
                                if (
is_array($tz) && isset($tz['mzone'])) {
                                    if (isset(
$date[0])) {
                                        if (isset(
$tz['from']) && (strcmp($date$tz['from']) < 0)) {
                                            continue;
                                        }
                                        if (isset(
$tz['to']) && (strcmp($date$tz['to']) >= 0)) {
                                            continue;
                                        }
                                    }
                                    
$metazoneCode $tz['mzone'];
                                    break;
                                }
                            }
                        }
                        if (isset(
$metazoneCode[0])) {
                            break;
                        }
                    }
                }
                if (!isset(
$metazoneCode[0])) {
                    foreach (
$phpNames as $phpName) {
                        foreach (
$data['metazones'] as $metazone) {
                            if (
strcasecmp($phpName$metazone['type']) === 0) {
                                
$metazoneCode $metazone['other'];
                                break;
                            }
                        }
                        if (isset(
$metazoneCode[0])) {
                            break;
                        }
                    }
                }
                if (!isset(
$metazoneCode[0])) {
                    
$metazoneCode $receivedPhpName;
                }
                if (isset(
$metazoneCode[0])) {
                    
$data Data::get('timeZoneNames'$locale);
                    if (isset(
$data['metazone'])) {
                        
$data $data['metazone'];
                        if (isset(
$data[$metazoneCode])) {
                            
$data $data[$metazoneCode];
                            if (isset(
$data[$width])) {
                                
$data $data[$width];
                                
$lookFor = array();
                                if (!empty(
$kind)) {
                                    
$lookFor[] = $kind;
                                }
                                
$lookFor[] = 'generic';
                                
$lookFor[] = 'standard';
                                
$lookFor[] = 'daylight';
                                foreach (
$lookFor as $lf) {
                                    if (isset(
$data[$lf])) {
                                        
$result $data[$lf];
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        
self::$timezoneCache[$cacheKey] = $result;

        return 
$result;
    }

    
/** @todo I can't find data for this */
    
public static function getTimezoneNameLocationSpecific($value$width 'long'$kind ''$locale '')
    {
        return 
'';
    }

    
/**
     * Returns the localized name of an exemplar city for a specific timezone.
     *
     * @param string|DateTime|DateTimeZone $value The php name of a timezone, or a DateTime instance or a DateTimeZone instance
     * @param bool $returnUnknownIfNotFound true If the exemplar city is not found, shall we return the translation of 'Unknown City'?
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if the exemplar city hasn't been found and $returnUnknownIfNotFound is false
     */
    
public static function getTimezoneExemplarCity($value$returnUnknownIfNotFound true$locale '')
    {
        
$result '';
        
$locale = empty($locale) ? Data::getDefaultLocale() : $locale;
        if (!empty(
$value)) {
            
$receivedPhpName '';
            if (
is_string($value)) {
                
$receivedPhpName $value;
            } elseif (
is_a($value'\DateTime')) {
                
$receivedPhpName = static::getTimezoneNameFromDatetime($value);
            } elseif (
is_a($value'\DateTimeZone')) {
                
$receivedPhpName = static::getTimezoneNameFromTimezone($value);
            }
            if (isset(
$receivedPhpName[0])) {
                
$phpNames = static::getTimezonesAliases($receivedPhpName);
                
$timeZoneNames Data::get('timeZoneNames'$locale);
                foreach (
$phpNames as $phpName) {
                    
$chunks array_merge(array('zone'), explode('/'$phpName));
                    
$data $timeZoneNames;
                    foreach (
$chunks as $chunk) {
                        if (isset(
$data[$chunk])) {
                            
$data $data[$chunk];
                        } else {
                            
$data null;
                        }
                        if (!
is_array($data)) {
                            break;
                        }
                    }
                    if (
is_array($data) && isset($data['exemplarCity'])) {
                        
$result $data['exemplarCity'];
                        break;
                    }
                }
            }
        }
        if ((!isset(
$result[0])) && $returnUnknownIfNotFound) {
            
$result 'Unknown City';
            
$s = static::getTimezoneExemplarCity('Etc/Unknown'false$locale);
            if (isset(
$s[0])) {
                
$result $s;
            }
        }

        return 
$result;
    }

    
/**
     * Returns true if a locale has a 12-hour clock, false if 24-hour clock.
     *
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return bool
     *
     * @throws PunicException Throws an exception in case of problems
     */
    
public static function has12HoursClock($locale '')
    {
        static 
$cache = array();
        
$locale = empty($locale) ? Data::getDefaultLocale() : $locale;
        if (!isset(
$cache[$locale])) {
            
$format = static::getTimeFormat('short'$locale);
            
$format str_replace("''"''$format);
            
$cache[$locale] = (strpos($format'a') === false) ? false true;
        }

        return 
$cache[$locale];
    }

    
/**
     * Retrieve the first weekday for a specific locale (from 0-Sunday to 6-Saturnday).
     *
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return int Returns a number from 0 (Sunday) to 7 (Saturnday)
     */
    
public static function getFirstWeekday($locale '')
    {
        static 
$cache = array();
        
$locale = empty($locale) ? Data::getDefaultLocale() : $locale;
        if (!isset(
$cache[$locale])) {
            
$result 0;
            
$data Data::getGeneric('weekData');
            
$i Data::getTerritoryNode($data['firstDay'], $locale);
            if (
is_int($i)) {
                
$result $i;
            }
            
$cache[$locale] = $result;
        }

        return 
$cache[$locale];
    }

    
/**
     * Returns the sorted list of weekdays, starting from {@link getFirstWeekday}.
     *
     * @param string|false $namesWidth If false you'll get only the list of weekday identifiers (for instance: [0, 1, 2, 3, 4, 5, 6]),
     * If it's a string it must be one accepted by {@link getWeekdayName}, and you'll get an array like this: [{id: 0, name: 'Monday', ..., {id: 6, name: 'Sunday'}]
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return array
     */
    
public static function getSortedWeekdays($namesWidth false$locale '')
    {
        
$codes = array();
        
$code = static::getFirstWeekday($locale);
        for (
$count 0$count 7; ++$count) {
            
$codes[] = $code;
            
$code += 1;
            if (
$code === 7) {
                
$code 0;
            }
        }
        if (empty(
$namesWidth)) {
            
$result $codes;
        } else {
            
$result = array();
            foreach (
$codes as $code) {
                
$result[] = array('id' => $code'name' => static::getWeekdayName($code$namesWidth$localetrue));
            }
        }

        return 
$result;
    }

    
/**
     * Get the ISO format for a date.
     *
     * @param string $width The format name; it can be 'full' (eg 'EEEE, MMMM d, y' - 'Wednesday, August 20, 2014'), 'long' (eg 'MMMM d, y' - 'August 20, 2014'), 'medium' (eg 'MMM d, y' - 'August 20, 2014') or 'short' (eg 'M/d/yy' - '8/20/14')
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns the requested ISO format
     *
     * @throws Exception Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function getDateFormat($width$locale '')
    {
        
$data Data::get('calendar'$locale);
        
$data $data['dateFormats'];
        if (!isset(
$data[$width])) {
            throw new 
ExceptionValueNotInList($widtharray_keys($data));
        }

        return 
$data[$width];
    }

    
/**
     * Get the ISO format for a time.
     *
     * @param string $width The format name; it can be 'full' (eg 'h:mm:ss a zzzz' - '11:42:13 AM GMT+2:00'), 'long' (eg 'h:mm:ss a z' - '11:42:13 AM GMT+2:00'), 'medium' (eg 'h:mm:ss a' - '11:42:13 AM') or 'short' (eg 'h:mm a' - '11:42 AM')
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns the requested ISO format
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function getTimeFormat($width$locale '')
    {
        
$data Data::get('calendar'$locale);
        
$data $data['timeFormats'];
        if (!isset(
$data[$width])) {
            throw new 
ExceptionValueNotInList($widtharray_keys($data));
        }

        return 
$data[$width];
    }

    
/**
     * Get the ISO format for a date/time.
     *
     * @param string $width The format name; it can be 'full', 'long', 'medium', 'short' or a combination for date+time like 'full|short' or a combination for format+date+time like 'full|full|short'
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns the requested ISO format
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function getDatetimeFormat($width$locale '')
    {
        return static::
getDatetimeFormatReal($width$locale);
    }

    protected static function 
getDatetimeFormatReal($width$locale ''$overrideDateFormat ''$overrideTimeFormat '')
    {
        
$chunks explode('|', @str_replace(array('*''^'), ''$width));
        switch (
count($chunks)) {
            case 
1:
                
$timeWidth $dateWidth $wholeWidth $chunks[0];
                break;
            case 
2:
                
$sortedChunks $chunks;
                
usort($sortedChunks, function ($a$b) {
                    
$cmp 0;
                    if (
$a !== $b) {
                        foreach (array(
'full''long''medium''short') as $w) {
                            if (
$a === $w) {
                                
$cmp = -1;
                                break;
                            }
                            if (
$b === $w) {
                                
$cmp 1;
                                break;
                            }
                        }
                    }

                    return 
$cmp;
                });
                
$wholeWidth $sortedChunks[0];
                
$dateWidth $chunks[0];
                
$timeWidth $chunks[1];
                break;
            case 
3:
                
$wholeWidth $chunks[0];
                
$dateWidth $chunks[1];
                
$timeWidth $chunks[2];
                break;
            default:
                throw new 
ExceptionBadArgumentType($width'pipe-separated list of strings (from 1 to 3 chunks)');
        }
        
$data Data::get('calendar'$locale);
        
$data $data['dateTimeFormats'];
        if (!isset(
$data[$wholeWidth])) {
            throw new 
ExceptionValueNotInList($wholeWidtharray_keys($data));
        }

        return 
sprintf(
            
$data[$wholeWidth],
            isset(
$overrideTimeFormat[0]) ? $overrideTimeFormat : static::getTimeFormat($timeWidth$locale),
            isset(
$overrideDateFormat[0]) ? $overrideDateFormat : static::getDateFormat($dateWidth$locale)
        );
    }

    
/**
     * Returns the difference in days between two dates (or between a date and today).
     *
     * @param DateTime $dateEnd The first date
     * @param DateTime|null $dateStart The final date (if it has a timezone different than $dateEnd, we'll use the one of $dateEnd)
     *
     * @return int Returns the diffence $dateEnd - $dateStart in days
     *
     * @throws ExceptionBadArgumentType
     */
    
public static function getDeltaDays($dateEnd$dateStart null)
    {
        if (!
is_a($dateEnd'\DateTime')) {
            throw new 
ExceptionBadArgumentType($dateEnd'\DateTime');
        }
        if (empty(
$dateStart) && ($dateStart !== 0) && ($dateStart !== '0')) {
            
$dateStart = new DateTime('now'$dateEnd->getTimezone());
        }
        if (!
is_a($dateStart'\DateTime')) {
            throw new 
ExceptionBadArgumentType($dateStart'\DateTime');
        }
        if (
$dateStart->getOffset() !== $dateEnd->getOffset()) {
            
$dateStart->setTimezone($dateEnd->getTimezone());
        }
        
$utc = new DateTimeZone('UTC');
        
$dateEndUTC = new DateTime($dateEnd->format('Y-m-d'), $utc);
        
$dateStartUTC = new DateTime($dateStart->format('Y-m-d'), $utc);
        
$seconds $dateEndUTC->getTimestamp() - $dateStartUTC->getTimestamp();

        return 
intval(round($seconds 86400));
    }

    
/**
     * Describe an interval between two dates (eg '2 days and 4 hours').
     *
     * @param DateTime $dateEnd The first date
     * @param DateTime|null $dateStart The final date (if it has a timezone different than $dateEnd, we'll use the one of $dateEnd)
     * @param int $maxParts The maximim parts (eg with 2 you may have '2 days and 4 hours', with 3 '2 days, 4 hours and 24 minutes')
     * @param string $width The format name; it can be 'long' (eg '3 seconds'), 'short' (eg '3 s') or 'narrow' (eg '3s')
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string
     *
     * @throws ExceptionBadArgumentType
     */
    
public static function describeInterval($dateEnd$dateStart null$maxParts 2$width 'short'$locale '')
    {
        if (!
is_a($dateEnd'\DateTime')) {
            throw new 
ExceptionBadArgumentType($dateEnd'\DateTime');
        }
        if (empty(
$dateStart) && ($dateStart !== 0) && ($dateStart !== '0')) {
            
$dateStart = new DateTime('now'$dateEnd->getTimezone());
        }
        if (!
is_a($dateStart'\DateTime')) {
            throw new 
ExceptionBadArgumentType($dateStart'\DateTime');
        }
        if (
$dateStart->getOffset() !== $dateEnd->getOffset()) {
            
$dateStart->setTimezone($dateEnd->getTimezone());
        }
        
$utc = new DateTimeZone('UTC');
        
$dateEndUTC = new DateTime($dateEnd->format('Y-m-d H:i:s'), $utc);
        
$dateStartUTC = new DateTime($dateStart->format('Y-m-d H:i:s'), $utc);

        
$parts = array();
        
$data Data::get('dateFields'$locale);
        if (
$dateEndUTC->getTimestamp() == $dateStartUTC->getTimestamp()) {
            
$parts[] = $data['second']['relative-type-0'];
        } else {
            
$diff $dateStartUTC->diff($dateEndUTCtrue);
            
$mostFar 0;
            
$maxDistance 3;
            if ((
$mostFar $maxDistance) && ($diff->0)) {
                
$parts[] = Unit::format($diff->y'duration/year'$width$locale);
                
$mostFar 0;
            } elseif (!empty(
$parts)) {
                ++
$mostFar;
            }
            if ((
$mostFar $maxDistance) && ($diff->0)) {
                
$parts[] = Unit::format($diff->m'duration/month'$width$locale);
                
$mostFar 0;
            } elseif (!empty(
$parts)) {
                ++
$mostFar;
            }
            if ((
$mostFar $maxDistance) && ($diff->0)) {
                
$parts[] = Unit::format($diff->d'duration/day'$width$locale);
                
$mostFar 0;
            } elseif (!empty(
$parts)) {
                ++
$mostFar;
            }
            if ((
$mostFar $maxDistance) && ($diff->0)) {
                
$parts[] = Unit::format($diff->h'duration/hour'$width$locale);
                
$mostFar 0;
            } elseif (!empty(
$parts)) {
                ++
$mostFar;
            }
            if ((
$mostFar $maxDistance) && ($diff->0)) {
                
$parts[] = Unit::format($diff->i'duration/minute'$width$locale);
                
$mostFar 0;
            } elseif (!empty(
$parts)) {
                ++
$mostFar;
            }
            if (empty(
$parts) || ($diff->0)) {
                
$parts[] = Unit::format($diff->s'duration/second'$width$locale);
            }
            if (
count($parts) > $maxParts) {
                
$parts array_slice($parts0$maxParts);
            }
        }
        switch (
$width) {
            case 
'narrow':
            case 
'short':
                
$joined Misc::joinUnits($parts$width$locale);
                break;
            default:
                
$joined Misc::join($parts$locale);
                break;
        }

        return 
$joined;
    }

    
/**
     * Format a date.
     *
     * @param DateTime $value The DateTime instance for which you want the localized textual representation
     * @param string $width The format name; it can be 'full' (eg 'EEEE, MMMM d, y' - 'Wednesday, August 20, 2014'), 'long' (eg 'MMMM d, y' - 'August 20, 2014'), 'medium' (eg 'MMM d, y' - 'August 20, 2014') or 'short' (eg 'M/d/yy' - '8/20/14').
     *                      You can also append a caret ('^') or an asterisk ('*') to $width. If so, special day names may be used (like 'Today', 'Yesterday', 'Tomorrow' with '^' and 'today', 'yesterday', 'tomorrow' width '*') instead of the date.
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function formatDate($value$width$locale '')
    {
        
$c is_string($width) ? @substr($width, -1) : '';
        if ((
$c === '^') || ($c === '*')) {
            
$dayName = static::getDateRelativeName($value, ($c === '^') ? true false$locale);
            if (isset(
$dayName[0])) {
                return 
$dayName;
            }
            
$width substr($width0, -1);
        }

        return static::
format(
            
$value,
            static::
getDateFormat($width$locale),
            
$locale
        
);
    }

    
/**
     * Format a date (extended version: various date/time representations - see toDateTime()).
     *
     * @param number|DateTime|string $value An Unix timestamp, a `DateTime` instance or a string accepted by {@link http://php.net/manual/function.strtotime.php strtotime}.
     * @param string $width The format name; it can be 'full' (eg 'EEEE, MMMM d, y' - 'Wednesday, August 20, 2014'), 'long' (eg 'MMMM d, y' - 'August 20, 2014'), 'medium' (eg 'MMM d, y' - 'August 20, 2014') or 'short' (eg 'M/d/yy' - '8/20/14')
     *                      You can also append a caret ('^') or an asterisk ('*') to $width. If so, special day names may be used (like 'Today', 'Yesterday', 'Tomorrow' with '^' and 'today', 'yesterday', 'tomorrow' width '*') instead of the date.
     * @param string|DateTimeZone $toTimezone The timezone to set; leave empty to use the default timezone (or the timezone associated to $value if it's already a DateTime)
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @see toDateTime()
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function formatDateEx($value$width$toTimezone ''$locale '')
    {
        return static::
formatDate(
            static::
toDateTime($value$toTimezone),
            
$width,
            
$locale
        
);
    }

    
/**
     * Format a time.
     *
     * @param DateTime $value The DateTime instance for which you want the localized textual representation
     * @param string $width The format name; it can be 'full' (eg 'h:mm:ss a zzzz' - '11:42:13 AM GMT+2:00'), 'long' (eg 'h:mm:ss a z' - '11:42:13 AM GMT+2:00'), 'medium' (eg 'h:mm:ss a' - '11:42:13 AM') or 'short' (eg 'h:mm a' - '11:42 AM')
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function formatTime($value$width$locale '')
    {
        return static::
format(
            
$value,
            static::
getTimeFormat($width$locale),
            
$locale
        
);
    }

    
/**
     * Format a time (extended version: various date/time representations - see toDateTime()).
     *
     * @param number|DateTime|string $value An Unix timestamp, a `DateTime` instance or a string accepted by {@link http://php.net/manual/function.strtotime.php strtotime}.
     * @param string $width The format name; it can be 'full' (eg 'h:mm:ss a zzzz' - '11:42:13 AM GMT+2:00'), 'long' (eg 'h:mm:ss a z' - '11:42:13 AM GMT+2:00'), 'medium' (eg 'h:mm:ss a' - '11:42:13 AM') or 'short' (eg 'h:mm a' - '11:42 AM')
     * @param string|DateTimeZone $toTimezone The timezone to set; leave empty to use the default timezone (or the timezone associated to $value if it's already a DateTime)
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @see toDateTime()
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function formatTimeEx($value$width$toTimezone ''$locale '')
    {
        return static::
formatTime(
            static::
toDateTime($value$toTimezone),
            
$width,
            
$locale
        
);
    }

    
/**
     * Format a date/time.
     *
     * @param DateTime $value The DateTime instance for which you want the localized textual representation
     * @param string $width The format name; it can be 'full', 'long', 'medium', 'short' or a combination for date+time like 'full|short' or a combination for format+date+time like 'full|full|short'
     *                      You can also append an asterisk ('*') to the date parh of $width. If so, special day names may be used (like 'Today', 'Yesterday', 'Tomorrow') instead of the date part.
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function formatDatetime($value$width$locale '')
    {
        
$overrideDateFormat '';
        if (
is_string($width)) {
            
$dateFormat '';
            
$chunks explode('|'$width);
            switch (
count($chunks)) {
                case 
1:
                case 
2:
                    
$dateFormat $chunks[0];
                    break;
                case 
3:
                    
$dateFormat $chunks[1];
                    break;
            }
            
$c = isset($dateFormat[0]) ? @substr($dateFormat, -1) : '';
            if ((
$c === '^') || ($c === '*')) {
                
$dayName = static::getDateRelativeName($value, ($c === '^') ? true false$locale);
                if (isset(
$dayName[0])) {
                    
$overrideDateFormat "'$dayName'";
                }
            }
        }

        return static::
format(
            
$value,
            static::
getDatetimeFormatReal($width$locale$overrideDateFormat),
            
$locale
        
);
    }

    
/**
     * Format a date/time (extended version: various date/time representations - see toDateTime()).
     *
     * @param number|DateTime|string $value An Unix timestamp, a `DateTime` instance or a string accepted by {@link http://php.net/manual/function.strtotime.php strtotime}.
     * @param string $width The format name; it can be 'full', 'long', 'medium', 'short' or a combination for date+time like 'full|short' or a combination for format+date+time like 'full|full|short'
     *                      You can also append an asterisk ('*') to the date parh of $width. If so, special day names may be used (like 'Today', 'Yesterday', 'Tomorrow') instead of the date part.
     * @param string|DateTimeZone $toTimezone The timezone to set; leave empty to use the default timezone (or the timezone associated to $value if it's already a DateTime)
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @see toDateTime()
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function formatDatetimeEx($value$width$toTimezone ''$locale '')
    {
        return static::
formatDatetime(
            static::
toDateTime($value$toTimezone),
            
$width,
            
$locale
        
);
    }

    
/**
     * Format a date and/or time.
     *
     * @param DateTime $value The DateTime instance for which you want the localized textual representation
     * @param string $format The ISO format that specify how to render the date/time. The following extra format chunks are available:
     * - 'P': ISO-8601 numeric representation of the day of the week (same as 'e' but not locale dependent)
     * - 'PP': Numeric representation of the day of the week, from 0 (for Sunday) to 6 (for Saturday)
     * - 'PPP': English ordinal suffix for the day of the month
     * - 'PPPP': The day of the year (starting from 0)
     * - 'PPPPP': Number of days in the given month
     * - 'PPPPPP': Whether it's a leap year: 1 if it is a leap year, 0 otherwise.
     * - 'PPPPPPP': Lowercase Ante meridiem and Post meridiem (English only, for other locales it's the same as 'a')
     * - 'PPPPPPPP': Swatch Internet time
     * - 'PPPPPPPPP': Microseconds
     * - 'PPPPPPPPPP': Whether or not the date is in daylight saving time    1 if Daylight Saving Time, 0 otherwise.
     * - 'PPPPPPPPPPP': Timezone offset in seconds
     * - 'PPPPPPPPPPPP': RFC 2822 formatted date (Example: 'Thu, 21 Dec 2000 16:01:07 +0200')
     * - 'PPPPPPPPPPPPP': Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function format($value$format$locale '')
    {
        static 
$decodeCache = array();
        static 
$decoderFunctions = array(
            
'G' => 'decodeEra',
            
'y' => 'decodeYear',
            
'Y' => 'decodeYearWeekOfYear',
            
'u' => 'decodeYearExtended',
            
'U' => 'decodeYearCyclicName',
            
'r' => 'decodeYearRelatedGregorian',
            
'Q' => 'decodeQuarter',
            
'q' => 'decodeQuarterAlone',
            
'M' => 'decodeMonth',
            
'L' => 'decodeMonthAlone',
            
'w' => 'decodeWeekOfYear',
            
'W' => 'decodeWeekOfMonth',
            
'd' => 'decodeDayOfMonth',
            
'D' => 'decodeDayOfYear',
            
'F' => 'decodeWeekdayInMonth',
            
'g' => 'decodeModifiedGiulianDay',
            
'E' => 'decodeDayOfWeek',
            
'e' => 'decodeDayOfWeekLocal',
            
'c' => 'decodeDayOfWeekLocalAlone',
            
'a' => 'decodeDayperiod',
            
'h' => 'decodeHour12',
            
'H' => 'decodeHour24',
            
'K' => 'decodeHour12From0',
            
'k' => 'decodeHour24From1',
            
'm' => 'decodeMinute',
            
's' => 'decodeSecond',
            
'S' => 'decodeFranctionsOfSeconds',
            
'A' => 'decodeMsecInDay',
            
'z' => 'decodeTimezoneNoLocationSpecific',
            
'Z' => 'decodeTimezoneDelta',
            
'O' => 'decodeTimezoneShortGMT',
            
'v' => 'decodeTimezoneNoLocationGeneric',
            
'V' => 'decodeTimezoneID',
            
'X' => 'decodeTimezoneWithTimeZ',
            
'x' => 'decodeTimezoneWithTime',
            
'P' => 'decodePunicExtension',
        );
        
$result '';
        if (!empty(
$value)) {
            if (!
is_a($value'\DateTime')) {
                throw new 
ExceptionBadArgumentType($value'\DateTime');
            }
            
$length is_string($format) ? strlen($format) : 0;
            if (
$length === 0) {
                throw new 
ExceptionBadArgumentType($format'date/time ISO format');
            }
            if (empty(
$locale)) {
                
$locale Data::getDefaultLocale();
            }
            if (!isset(
$decodeCache[$locale])) {
                
$decodeCache[$locale] = array();
            }
            if (!isset(
$decodeCache[$locale][$format])) {
                
$decoder = array();
                
$lengthM1 $length 1;
                
$quoted false;
                for (
$index 0$index $length; ++$index) {
                    
$char $format[$index];
                    if (
$char === "'") {
                        if (
$quoted) {
                            
$quoted false;
                        } elseif ((
$index $lengthM1) && ($format[$index 1] === "'")) {
                            
$decoder[] = "'";
                            ++
$index;
                        } else {
                            
$quoted true;
                        }
                    } elseif (
$quoted) {
                        
$decoder[] = $char;
                    } else {
                        
$count 1;
                        for (
$j $index 1; ($j $length) && ($format[$j] === $char); ++$j) {
                            ++
$count;
                            ++
$index;
                        }
                        if (isset(
$decoderFunctions[$char])) {
                            
$decoder[] = array($decoderFunctions[$char], $count);
                        } else {
                            
$decoder[] = str_repeat($char$count);
                        }
                    }
                }
                
$decodeCache[$locale][$format] = $decoder;
            } else {
                
$decoder $decodeCache[$locale][$format];
            }
            foreach (
$decoder as $chunk) {
                if (
is_string($chunk)) {
                    
$result .= $chunk;
                } else {
                    
$functionName $chunk[0];
                    
$count $chunk[1];
                    
$result .= static::$functionName($value$count$locale);
                }
            }
        }

        return 
$result;
    }
    
/**
     * Format a date and/or time (extended version: various date/time representations - see toDateTime()).
     *
     * @param number|DateTime|string $value An Unix timestamp, a `DateTime` instance or a string accepted by {@link http://php.net/manual/function.strtotime.php strtotime}.
     * @param string $format The ISO format that specify how to render the date/time. The following extra format chunks are valid:
     * - 'P': ISO-8601 numeric representation of the day of the week (same as 'e' but not locale dependent)
     * - 'PP': Numeric representation of the day of the week, from 0 (for Sunday) to 6 (for Saturday)
     * - 'PPP': English ordinal suffix for the day of the month
     * - 'PPPP': The day of the year (starting from 0)
     * - 'PPPPP': Number of days in the given month
     * - 'PPPPPP': Whether it's a leap year: 1 if it is a leap year, 0 otherwise.
     * - 'PPPPPPP': Lowercase Ante meridiem and Post meridiem (English only, for other locales it's the same as 'a')
     * - 'PPPPPPPP': Swatch Internet time
     * - 'PPPPPPPPP': Microseconds
     * - 'PPPPPPPPPP': Whether or not the date is in daylight saving time    1 if Daylight Saving Time, 0 otherwise.
     * - 'PPPPPPPPPPP': Timezone offset in seconds
     * - 'PPPPPPPPPPPP': RFC 2822 formatted date (Example: 'Thu, 21 Dec 2000 16:01:07 +0200')
     * - 'PPPPPPPPPPPPP': Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)
     * @param string|DateTimeZone $toTimezone The timezone to set; leave empty to use the default timezone (or the timezone associated to $value if it's already a DateTime)
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns an empty string if $value is empty, the localized textual representation otherwise
     *
     * @throws PunicException Throws an exception in case of problems
     *
     * @link http://cldr.unicode.org/translation/date-time-patterns
     * @link http://cldr.unicode.org/translation/date-time
     * @link http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
     */
    
public static function formatEx($value$format$toTimezone ''$locale '')
    {
        return static::
format(
            static::
toDateTime($value$toTimezone),
            
$format,
            
$locale
        
);
    }

    
/**
     * Retrieve the relative day name (eg 'yesterday', 'tomorrow'), if available.
     *
     * @param DateTime $datetime The date for which you want the relative day name
     * @param bool $ucFirst Force first letter to be upper case?
     * @param string $locale The locale to use. If empty we'll use the default locale set in PunicData
     *
     * @return string Returns the relative name if available, otherwise returns an empty string
     */
    
public static function getDateRelativeName($datetime$ucFirst false$locale '')
    {
        
$result '';
        
$deltaDays = static::getDeltaDays($datetime);
        
$data Data::get('dateFields'$locale);
        if (isset(
$data['day'])) {
            
$data $data['day'];
            
$key "relative-type-$deltaDays";
            if (isset(
$data[$key])) {
                
$result $data[$key];
                if (
$ucFirst) {
                    
$result Misc::fixCase($result'titlecase-firstword');
                }
            }
        }

        return 
$result;
    }

    protected static function 
decodeDayOfWeek(DateTime $value$count$locale$standAlone false)
    {
        switch (
$count) {
            case 
1:
            case 
2:
            case 
3:
                return static::
getWeekdayName($value'abbreviated'$locale$standAlone);
            case 
4:
                return static::
getWeekdayName($value'wide'$locale$standAlone);
            case 
5:
                return static::
getWeekdayName($value'narrow'$locale$standAlone);
            case 
6:
                return static::
getWeekdayName($value'short'$locale$standAlone);
            default:
                throw new 
ExceptionValueNotInList($count, array(123456));
        }
    }

    protected static function 
decodeDayOfWeekLocal(DateTime $value$count$locale$standAlone false)
    {
        switch (
$count) {
            case 
1:
            case 
2:
                
$weekDay intval($value->format('w'));
                
$firstWeekdayForCountry = static::getFirstWeekday($locale);
                
$localWeekday + (($weekDay $firstWeekdayForCountry) % 7);

                return 
str_pad(strval($localWeekday), $count'0'STR_PAD_LEFT);
            default:
                return static::
decodeDayOfWeek($value$count$locale$standAlone);
        }
    }

    protected static function 
decodeDayOfWeekLocalAlone(DateTime $value$count$locale)
    {
        return static::
decodeDayOfWeekLocal($value$count$localetrue);
    }

    protected static function 
decodeDayOfMonth(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
$value->format('j');
            case 
2:
                return 
$value->format('d');
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeMonth(DateTime $value$count$locale$standAlone false)
    {
        switch (
$count) {
            case 
1:
                return 
$value->format('n');
            case 
2:
                return 
$value->format('m');
            case 
3:
                return static::
getMonthName($value'abbreviated'$locale$standAlone);
            case 
4:
                return static::
getMonthName($value'wide'$locale$standAlone);
            case 
5:
                return static::
getMonthName($value'narrow'$locale$standAlone);
            default:
                throw new 
ExceptionValueNotInList($count, array(12345));
        }
    }

    protected static function 
decodeMonthAlone(DateTime $value$count$locale)
    {
        return static::
decodeMonth($value$count$localetrue);
    }

    protected static function 
decodeYear(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
strval(intval($value->format('Y')));
            case 
2:
                return 
$value->format('y');
            default:
                
$s $value->format('Y');
                if (!isset(
$s[$count])) {
                    
$s str_pad($s$count'0'STR_PAD_LEFT);
                }

                return 
$s;
        }
    }

    protected static function 
decodeHour12(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
$value->format('g');
            case 
2:
                return 
$value->format('h');
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeDayperiod(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return static::
getDayperiodName($value'abbreviated'$locale);
            default:
                throw new 
ExceptionValueNotInList($count, array(1));
        }
    }

    protected static function 
decodeHour24(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
$value->format('G');
            case 
2:
                return 
$value->format('H');
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeHour12From0(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
            case 
2:
                return 
str_pad(strval(intval($value->format('G')) % 12), $count'0'STR_PAD_LEFT);
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeHour24From1(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
            case 
2:
                return 
str_pad(strval(intval($value->format('G'))), $count'0'STR_PAD_LEFT);
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeMinute(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
strval(intval($value->format('i')));
            case 
2:
                return 
$value->format('i');
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeSecond(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
strval(intval($value->format('s')));
            case 
2:
                return 
$value->format('s');
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeTimezoneNoLocationSpecific(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
            case 
2:
            case 
3:
                
$tz = static::getTimezoneNameNoLocationSpecific($value'short'''$locale);
                if (!isset(
$tz[0])) {
                    
$tz = static::decodeTimezoneShortGMT($value1$locale);
                }
                break;
            case 
4:
                
$tz = static::getTimezoneNameNoLocationSpecific($value'long'''$locale);
                if (!isset(
$tz[0])) {
                    
$tz = static::decodeTimezoneShortGMT($value4$locale);
                }
                break;
            default:
                throw new 
ExceptionValueNotInList($count, array(1234));
        }

        return 
$tz;
    }

    protected static function 
decodeTimezoneShortGMT(DateTime $value$count$locale)
    {
        
$offset $value->getOffset();
        
$sign = ($offset 0) ? '-' '+';
        
$seconds abs($offset);
        
$hours intval(floor($seconds 3600));
        
$seconds -= $hours 3600;
        
$minutes intval(floor($seconds 60));
        
$data Data::get('timeZoneNames'$locale);
        
$format = isset($data['gmtFormat']) ? $data['gmtFormat'] : 'GMT%1$s';
        switch (
$count) {
            case 
1:
                return 
sprintf($format$sign.$hours.(($minutes === 0) ? '' : (':'.substr('0'.$minutes, -2))));
            case 
4:
                return 
sprintf($format$sign.$hours.':'.substr('0'.$minutes, -2));
            default:
                throw new 
ExceptionValueNotInList($count, array(14));
        }
    }

    protected static function 
decodeEra(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
            case 
2:
            case 
3:
                return static::
getEraName($value'abbreviated'$locale);
            case 
4:
                return static::
getEraName($value'wide'$locale);
            case 
5:
                return static::
getEraName($value'narrow'$locale);
            default:
                throw new 
ExceptionValueNotInList($count, array(12345));
        }
    }

    protected static function 
decodeYearWeekOfYear(DateTime $value$count$locale)
    {
        
$y $value->format('o');
        if (
$count === 2) {
            
$y substr('0'.$y, -2);
        } else {
            if (!isset(
$y[$count])) {
                
$y str_pad($y$count'0'STR_PAD_LEFT);
            }
        }

        return 
$y;
    }

    
/**
     * Note: we assume Gregorian calendar here.
     */
    
protected static function decodeYearExtended(DateTime $value$count$locale)
    {
        return static::
decodeYear($value$count$locale);
    }

    
/**
     * Note: we assume Gregorian calendar here.
     */
    
protected static function decodeYearRelatedGregorian(DateTime $value$count$locale)
    {
        return static::
decodeYearExtended($value$count$locale);
    }

    protected static function 
decodeQuarter(DateTime $value$count$locale$standAlone false)
    {
        
$quarter intval(floor((intval($value->format('n')) - 1) / 3));
        switch (
$count) {
            case 
1:
                return 
strval($quarter);
            case 
2:
                return 
'0'.strval($quarter);
            case 
3:
                return static::
getQuarterName($quarter'abbreviated'$locale$standAlone);
            case 
4:
                return static::
getQuarterName($quarter'wide'$locale$standAlone);
            case 
5:
                return static::
getQuarterName($quarter'narrow'$locale$standAlone);
            default:
                throw new 
ExceptionValueNotInList($count, array(12345));
        }
    }

    protected static function 
decodeQuarterAlone(DateTime $value$count$locale)
    {
        return static::
decodeQuarter($value$count$localetrue);
    }

    protected static function 
decodeWeekOfYear(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
strval(intval($value->format('W')));
            case 
2:
                return 
$value->format('W');
            default:
                throw new 
ExceptionValueNotInList($count, array(12));
        }
    }

    protected static function 
decodeDayOfYear(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
            case 
2:
            case 
3:
                return 
str_pad(strval($value->format('z')), $count'0'STR_PAD_LEFT);
            default:
                throw new 
ExceptionValueNotInList($count, array(123));
        }
    }

    protected static function 
decodeWeekdayInMonth(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
            case 
2:
            case 
3:
                
$dom intval($value->format('j'));
                
$wim intval(floor(($dom 1) / 7));

                return 
str_pad(strval($wim), $count'0'STR_PAD_LEFT);
            default:
                throw new 
ExceptionValueNotInList($count, array(123));
        }
    }

    protected static function 
decodeFranctionsOfSeconds(DateTime $value$count$locale)
    {
        
$us intval($value->format('u'));
        if (
$count >= 6) {
            
$result str_pad(strval($us), $count'0'STR_PAD_RIGHT);
        } elseif (
$count >= 1) {
            
$v intval(floor($us pow(10$count)));
            
$result str_pad(strval($v), $count'0'STR_PAD_LEFT);
        } else {
            
$result '';
        }

        return 
$result;
    }

    protected static function 
decodeMsecInDay(DateTime $value$count$locale)
    {
        
$hours intval($value->format('G'));
        
$minutes $hours 60 intval($value->format('i'));
        
$seconds $minutes 60 intval($value->format('s'));
        
$milliseconds $seconds 1000 intval(floor(intval($value->format('u')) / 1000));

        return 
str_pad(strval($milliseconds), $count'0'STR_PAD_LEFT);
    }

    protected static function 
decodeTimezoneDelta(DateTime $value$count$locale)
    {
        
$offset $value->getOffset();
        
$sign = ($offset 0) ? '-' '+';
        
$seconds abs($offset);
        
$hours intval(floor($seconds 3600));
        
$seconds -= $hours 3600;
        
$minutes intval(floor($seconds 60));
        
$seconds -= $minutes 60;
        
$partsWithoutSeconds = array();
        
$partsWithoutSeconds[] = $sign.substr('0'.strval($hours), -2);
        
$partsWithoutSeconds[] = substr('0'.strval($minutes), -2);
        
$partsMaybeWithSeconds $partsWithoutSeconds;
        
/* @TZWS
        if ($seconds > 0) {
            $partsMaybeWithSeconds[] = substr('0' . strval($seconds), -2);
        }
        */
        
switch ($count) {
            case 
1:
            case 
2:
            case 
3:
                return 
implode(''$partsMaybeWithSeconds);
            case 
4:
                
$data Data::get('timeZoneNames'$locale);
                
$format = isset($data['gmtFormat']) ? $data['gmtFormat'] : 'GMT%1$s';

                return 
sprintf($formatimplode(':'$partsWithoutSeconds));
            case 
5:
                return 
implode(':'$partsMaybeWithSeconds);
            default:
                throw new 
ExceptionValueNotInList($count, array(12345));
        }
    }

    protected static function 
decodeTimezoneNoLocationGeneric(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                
$tz = static::getTimezoneNameNoLocationSpecific($value'short''generic'$locale);
                if (!isset(
$tz[0])) {
                    
$tz = static::decodeTimezoneID($value4$locale);
                }
                break;
            case 
4:
                
$tz = static::getTimezoneNameNoLocationSpecific($value'long''generic'$locale);
                if (!isset(
$tz[0])) {
                    
$tz = static::decodeTimezoneID($value4$locale);
                }
                break;
            default:
                throw new 
ExceptionValueNotInList($count, array(14));
        }

        return 
$tz;
    }

    protected static function 
decodeTimezoneID(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                
$result 'unk';
                break;
            case 
2:
                
$result = static::getTimezoneNameFromDatetime($value);
                break;
            case 
3:
                
$result = static::getTimezoneExemplarCity($valuetrue$locale);
                break;
            case 
4:
                
$result = static::getTimezoneNameLocationSpecific($value'short''generic'$locale);
                if (!isset(
$result[0])) {
                    
$result = static::decodeTimezoneShortGMT($value4$locale);
                }
                break;
            default:
                throw new 
ExceptionValueNotInList($count, array(1234));
        }

        return 
$result;
    }

    protected static function 
decodeTimezoneWithTime(DateTime $value$count$locale$zForZero false)
    {
        
$offset $value->getOffset();
        
$useZ = ($zForZero && ($offset === 0)) ? true false;
        
$sign = ($offset 0) ? '-' '+';
        
$seconds abs($offset);
        
$hours intval(floor($seconds 3600));
        
$seconds -= $hours 3600;
        
$minutes intval(floor($seconds 60));
        
$seconds -= $minutes 60;
        
$hours2 $sign.substr('0'.strval($hours), -2);
        
$minutes2 substr('0'.strval($minutes), -2);
        
/* @TZWS
        $seconds2 = substr('0' . strval($seconds), -2);
        */
        
$hmMaybe = array($hours2);
        if (
$minutes 0) {
            
$hmMaybe[] = $minutes2;
        }
        
$hmsMaybe = array($hours2$minutes2);
        
/* @TZWS
        if ($seconds > 0) {
            $hmsMaybe[] = $seconds2;
        }
        */
        
switch ($count) {
            case 
1:
                
$result $useZ 'Z' implode(''$hmMaybe);
                break;
            case 
2:
                
$result $useZ 'Z' "$hours2$minutes2";
                break;
            case 
3:
                
$result $useZ 'Z' "$hours2:$minutes2";
                break;
            case 
4:
                
$result $useZ 'Z' implode(''$hmsMaybe);
                break;
            case 
5:
                
$result $useZ 'Z' implode(':'$hmsMaybe);
                break;
            default:
                throw new 
ExceptionValueNotInList($count, array(12345));
        }

        return 
$result;
    }

    protected static function 
decodeTimezoneWithTimeZ(DateTime $value$count$locale)
    {
        return static::
decodeTimezoneWithTime($value$count$localetrue);
    }

    
/** @todo */
    
protected static function decodeWeekOfMonth(DateTime $value$count$locale)
    {
        throw new 
ExceptionNotImplemented(__METHOD__);
    }
    
/** @todo */
    
protected static function decodeYearCyclicName()
    {
        throw new 
ExceptionNotImplemented(__METHOD__);
    }
    
/** @todo */
    
protected static function decodeModifiedGiulianDay()
    {
        throw new 
ExceptionNotImplemented(__METHOD__);
    }

    protected static function 
getTimezonesAliases($phpTimezoneName)
    {
        
$result = array($phpTimezoneName);
        switch (
$phpTimezoneName) {
            case 
'Africa/Asmara':
                
$result[] = 'Africa/Asmera';
                break;
            case 
'America/Atikokan':
                
$result[] = 'America/Coral_Harbour';
                break;
            case 
'Asia/Ho_Chi_Minh':
                
$result[] = 'Asia/Saigon';
                break;
            case 
'Asia/Kathmandu':
                
$result[] = 'Asia/Katmandu';
                break;
            case 
'Asia/Kolkata':
                
$result[] = 'Asia/Calcutta';
                break;
            case 
'Atlantic/Faroe':
                
$result[] = 'Atlantic/Faeroe';
                break;
            case 
'Pacific/Chuuk':
                
$result[] = 'Pacific/Truk';
                break;
            case 
'Pacific/Pohnpei':
                
$result[] = 'Pacific/Ponape';
                break;
            case 
'America/Argentina/Buenos_Aires':
                
$result[] = 'America/Buenos_Aires';
                break;
            case 
'America/Argentina/Catamarca':
                
$result[] = 'America/Catamarca';
                break;
            case 
'America/Argentina/Cordoba':
                
$result[] = 'America/Cordoba';
                break;
            case 
'America/Argentina/Jujuy':
                
$result[] = 'America/Jujuy';
                break;
            case 
'America/Argentina/Mendoza':
                
$result[] = 'America/Mendoza';
                break;
            case 
'America/Indiana/Indianapolis':
                
$result[] = 'America/Indianapolis';
                break;
            case 
'America/Kentucky/Louisville':
                
$result[] = 'America/Louisville';
                break;
        }

        return 
$result;
    }

    protected static function 
decodePunicExtension(DateTime $value$count$locale)
    {
        switch (
$count) {
            case 
1:
                return 
$value->format('N');
            case 
2:
                return 
$value->format('w');
            case 
3:
                return (
stripos($locale'en') === 0) ? $value->format('S') : '';
            case 
4:
                return 
$value->format('z');
            case 
5:
                return 
$value->format('t');
            case 
6:
                return 
$value->format('L');
            case 
7:
                
$result self::decodeDayperiod($value1$locale);
                if (
stripos($locale'en') === 0) {
                    
$result strtolower($result);
                }

                return 
$result;
            case 
8:
                return 
$value->format('B');
            case 
9:
                return 
$value->format('u');
            case 
10:
                return 
$value->format('I');
            case 
11:
                return 
$value->format('Z');
            case 
12:
                return 
$value->format('r');
            case 
13:
                return 
$value->format('U');
            default:
                throw new 
ExceptionValueNotInList($count, array(12345678910111213));
        }
    }

    protected static function 
getTimezoneNameFromDatetime(DateTime $dt)
    {
        if (
defined('HHVM_VERSION')) {
            
$result $dt->format('e');
            if (!
preg_match('/[0-9][0-9]/'$result)) {
                
$result $dt->getTimezone()->getName();
            }
        } else {
            
$result $dt->getTimezone()->getName();
        }

        return 
$result;
    }

    protected static function 
getTimezoneNameFromTimezone(DateTimeZone $tz)
    {
        if (
defined('HHVM_VERSION')) {
            
$testDT = new DateTime('now'$tz);
            
$result $testDT->format('e');
            if (!
preg_match('/[0-9][0-9]/'$result)) {
                
$result $tz->getName();
            }
        } else {
            
$result $tz->getName();
        }

        return 
$result;
    }
}
Онлайн: 1
Реклама