class DatexFormatter in Datex 7
Date tools for Jalali Dates.
Hierarchy
- class \DatexFormatter
Expanded class hierarchy of DatexFormatter
File
- datex_api/
datex_api_classes.inc, line 27 - API and helper functions used by other datex modules.
View source
class DatexFormatter {
protected static $daysInGregorianMonth = array(
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
);
protected static $daysInJalaliMonth = array(
31,
31,
31,
31,
31,
31,
30,
30,
30,
30,
30,
29,
);
/**
* Similar to php date_format.
*
* @param mixed $date
* Date to format. For a list of accepted dates see ObjectFromDate.
* @param DateTimeZone $tz
* DateTimeZone object or name (string) of timezone area.
* @param bool $use_intl
* Wheter to use PHP-Intl or not, recomended: TRUE.
* @param array $intl_args
* Arguments passed to PHP-Intl formatter.
*
* @return string
* formatted date.
*/
public static function format($date, $format, $tz = NULL, $use_intl = DATEX_USE_INTL, $intl_args = array()) {
if (self::hasINTL() && $use_intl) {
return self::formatINTL($date, $format, $tz, $intl_args);
}
else {
return self::formatPHP($date, $format, $tz);
}
}
/**
* Returns array containing names of days and monthes in persian.
*
* @todo replace with a translator function like Drupal's t().
*/
public static function persianDateNames() {
static $names = NULL;
if (!$names) {
$names = array(
'months' => array(
1 => 'فروردین',
2 => 'اردیبهشت',
3 => 'خرداد',
4 => 'تیر',
5 => 'مرداد',
6 => 'شهریور',
7 => 'مهر',
8 => 'آبان',
9 => 'آذر',
10 => 'دی',
11 => 'بهمن',
12 => 'اسفند',
),
'ampm' => array(
'am' => 'ق.ظ',
'pm' => 'ب.ظ',
),
'day_abbr' => array(
6 => 'ش.',
7 => 'ی.',
1 => 'د.',
2 => 'س.',
3 => 'چ.',
4 => 'پ.',
5 => 'ج.',
),
'day' => array(
6 => 'شنبه',
7 => 'یکشنبه',
1 => 'دوشنبه',
2 => 'سهشنبه',
3 => 'چهارشنبه',
4 => 'پنجشنبه',
5 => 'جمعه',
),
'tz' => 'تهران',
);
}
return $names;
}
/**
* Converts a Gregorian date to Jalali.
*/
public static function toJalali($gregorian_year = 0, $gregorian_month = 0, $gregorian_day = 0) {
$now = getdate();
$gregorian_year = ($gregorian_year ? $gregorian_year : $now['year']) - 1600;
$gregorian_month = ($gregorian_month ? $gregorian_month : $now['mon']) - 1;
$gregorian_day = ($gregorian_day ? $gregorian_day : $now['mday']) - 1;
$gregorian_day_no = 365 * $gregorian_year + intval(($gregorian_year + 3) / 4) - intval(($gregorian_year + 99) / 100) + intval(($gregorian_year + 399) / 400);
for ($i = 0; $i < $gregorian_month; ++$i) {
$gregorian_day_no += self::$daysInGregorianMonth[$i];
}
if ($gregorian_month > 1 && ($gregorian_year % 4 == 0 && $gregorian_year % 100 != 0) || $gregorian_year % 400 == 0) {
// Leap and after Feb.
$gregorian_day_no++;
}
$gregorian_day_no += $gregorian_day;
$jalali_day_no = $gregorian_day_no - 79;
$j_np = intval($jalali_day_no / 12053);
$jalali_day_no = $jalali_day_no % 12053;
$j_year = 979 + 33 * $j_np + 4 * intval($jalali_day_no / 1461);
$jalali_day_no %= 1461;
if ($jalali_day_no >= 366) {
$j_year += intval(($jalali_day_no - 1) / 365);
$jalali_day_no = ($jalali_day_no - 1) % 365;
}
for ($i = 0; $i < 11 && $jalali_day_no >= self::$daysInJalaliMonth[$i]; ++$i) {
$jalali_day_no -= self::$daysInJalaliMonth[$i];
}
$j_month = $i + 1;
$j_day = $jalali_day_no + 1;
return array(
'day' => $j_day,
'month' => $j_month,
'year' => $j_year,
);
}
/**
* Converts a Jalali date to Gregorian.
*/
public static function toGregorian($jalali_year = 0, $jalali_month = 0, $jalali_day = 0) {
$now = self::toJalali();
$jalali_year = ($jalali_year ? $jalali_year : $now['year']) - 979;
$jalali_month = ($jalali_month ? $jalali_month : $now['month']) - 1;
$jalali_day = ($jalali_day ? $jalali_day : $now['day']) - 1;
$jalali_day_no = 365 * $jalali_year + intval($jalali_year / 33) * 8 + intval(($jalali_year % 33 + 3) / 4);
for ($i = 0; $i < $jalali_month; ++$i) {
$jalali_day_no += self::$daysInJalaliMonth[$i];
}
$jalali_day_no += $jalali_day;
$gregorian_day_no = $jalali_day_no + 79;
$g_year = 1600 + 400 * intval($gregorian_day_no / 146097);
$gregorian_day_no = $gregorian_day_no % 146097;
$leap = TRUE;
if ($gregorian_day_no >= 36525) {
$gregorian_day_no--;
$g_year += 100 * intval($gregorian_day_no / 36524);
$gregorian_day_no = $gregorian_day_no % 36524;
if ($gregorian_day_no >= 365) {
$gregorian_day_no++;
}
else {
$leap = FALSE;
}
}
$g_year += 4 * intval($gregorian_day_no / 1461);
$gregorian_day_no %= 1461;
if ($gregorian_day_no >= 366) {
$leap = FALSE;
$gregorian_day_no--;
$g_year += intval($gregorian_day_no / 365);
$gregorian_day_no = $gregorian_day_no % 365;
}
for ($i = 0; $gregorian_day_no >= self::$daysInGregorianMonth[$i] + ($i == 1 && $leap); $i++) {
$gregorian_day_no -= self::$daysInGregorianMonth[$i] + ($i == 1 && $leap);
}
$g_month = $i + 1;
$g_day = $gregorian_day_no + 1;
return array(
'year' => $g_year,
'month' => $g_month,
'day' => $g_day,
);
}
/**
* Converts date format string (like 'Y-m-d') to it's PHP-Intl equivilant.
*
* @param string $format
* Format accepted by php date_format.
*
* @return string
* Format accepted by PHP-Intl date formatter (ICU).
*/
public static function phpToIntl($format) {
static $format_map = NULL;
if (!$format_map) {
$format_map = array(
'd' => 'dd',
'D' => 'EEE',
'j' => 'd',
'l' => 'EEEE',
'N' => 'e',
'S' => 'LLLL',
'w' => '',
'z' => 'D',
'W' => 'w',
'm' => 'MM',
'M' => 'MMM',
'F' => 'MMMM',
'n' => 'M',
't' => '',
'L' => '',
'o' => 'yyyy',
'y' => 'yy',
'Y' => 'YYYY',
'a' => 'a',
'A' => 'a',
'B' => '',
'g' => 'h',
'G' => 'H',
'h' => 'hh',
'H' => 'HH',
'i' => 'mm',
's' => 'ss',
'u' => 'SSSSSS',
'e' => 'z',
'I' => '',
'O' => 'Z',
'P' => 'ZZZZ',
'T' => 'v',
'Z' => '',
'c' => '',
'r' => '',
'U' => '',
' ' => ' ',
'-' => '-',
'.' => '.',
'-' => '-',
':' => ':',
);
}
$replace_pattern = '/[^ \\:\\-\\/\\.\\\\dDjlNSwzWmMFntLoyYaABgGhHisueIOPTZcrU]/';
return strtr(preg_replace($replace_pattern, '', $format), $format_map);
}
/**
* Formats a date according to format given.
*
* This function uses internal
* methods for converting, See DatexFormatter::formatINTL is suggested
* instead.
*/
public static function formatPHP($date, $format, $tz) {
$persian_date_names = self::persianDateNames();
// For anyone reading this comment: Passing a DateTimeZone to datetime
// constructor has no effect on it! You MUST use setTimezone to set a
// tz on the stupid object.
// Tested on PHP 5.4.15 (built: May 12 2013 13:11:23) Archlinux.
$date = self::ObjectFromDate($date);
if ($tz) {
$tz = self::getTzObject($tz);
$date
->setTimezone($tz);
}
$gregorian_date = array(
'd' => intval($date
->format('j')),
'm' => intval($date
->format('n')),
'Y' => intval($date
->format('Y')),
);
$jalali_date = self::toJalali($gregorian_date['Y'], $gregorian_date['m'], $gregorian_date['d']);
$z = $jalali_date['month'] <= 6 ? $jalali_date['month'] * 31 + $jalali_date['day'] : 186 + (($jalali_date['month'] - 6) * 30 + $jalali_date['day']);
$format = preg_replace('/[\\\\][a-z]/', '', $format);
$is_leap = self::isLeap($jalali_date['year']) ? 1 : 0;
$replacements = array(
'd' => sprintf('%02d', $jalali_date['day']),
'D' => $persian_date_names['day_abbr'][$date
->format('N')],
'j' => $jalali_date['day'],
'l' => $persian_date_names['day'][$date
->format('N')],
'S' => $persian_date_names['day_abbr'][$date
->format('N')],
'F' => $persian_date_names['months'][$jalali_date['month']],
'm' => sprintf('%02d', $jalali_date['month']),
'n' => $jalali_date['month'],
'L' => str_replace('L', $is_leap, $format),
'Y' => $jalali_date['year'],
'y' => $jalali_date['year'],
'o' => $jalali_date['year'],
'a' => $persian_date_names['ampm'][$date
->format('a')],
'A' => $persian_date_names['ampm'][$date
->format('a')],
'B' => $persian_date_names['ampm'][$date
->format('a')],
'c' => $jalali_date['year'] . '-' . $jalali_date['month'] . '-' . $jalali_date['day'] . 'T' . $date
->format('H:i:sP'),
'g' => $date
->format('g'),
'G' => $date
->format('G'),
'h' => $date
->format('h'),
'H' => $date
->format('H'),
'i' => $date
->format('i'),
's' => $date
->format('s'),
'u' => $date
->format('u'),
'I' => $date
->format('I'),
'O' => $date
->format('O'),
'P' => $date
->format('P'),
'T' => $date
->format('T'),
'Z' => $date
->format('Z'),
'U' => $date
->format('U'),
'w' => $date
->format('w'),
'N' => $date
->format('N'),
'e' => $date
->format('e'),
'z' => $z,
'W' => ceil($z / 7),
't' => self::$daysInJalaliMonth[$jalali_date['month'] - 1],
);
$replacements['r'] = $persian_date_names['day_abbr'][$date
->format('N')] . ', ' . $jalali_date['day'] . ' ' . $persian_date_names['months'][$jalali_date['month']] . ' ' . $jalali_date['year'] . $date
->format('H:i:s P');
if ($is_leap && $jalali_date['month'] == 12) {
$replacements['t'] = 30;
}
else {
$replacements['t'] = self::$daysInJalaliMonth[$jalali_date['month'] - 1];
}
return strtr($format, $replacements);
}
/**
* Formats a date according to format given.
*
* This function uses php-intl methods for converting. PECL package php-intl
* must be enabled.
*/
public static function formatINTL($date, $format, $tz, $formatter_args) {
$intl_formatter = new IntlDateFormatter("fa_IR@calendar=persian", IntlDateFormatter::FULL, IntlDateFormatter::FULL, self::getTzString($tz), IntlDateFormatter::TRADITIONAL, self::phpToIntl($format));
$date = $intl_formatter
->format(self::getTimestamp($date));
// By default undecorates decorated date by intl.
return isset($formatter_args['decor']) ? $date : self::decor($date, FALSE);
}
/**
* Created a DateTime object containing date from $date.
*
* Accepted date formats are an integer (as timestamp), A DatexObject object,
* A DateTime or DateObject object or an array.
*
* If an array is given and $gregorian is set to FALSE, Then Object is
* extracted from a Jalali date. This is the only way of getting date from
* jalali date.
*/
public static function ObjectFromDate($date = NULL, $tz = NULL, $gregorian = TRUE) {
// If is a number or a timestamp string: like 432432 or '432432', it
// will become like '@432432'. This case covers both integer and string.
if (is_numeric($date)) {
$date = '@' . $date;
}
elseif (is_object($date)) {
$date = '@' . $date
->format('U');
}
elseif (is_array($date)) {
if (!$gregorian) {
$greg_date = self::toGregorian(@$date['year'], @$date['month'], @$date['day']);
$year = $greg_date['year'];
$month = $greg_date['month'];
$day = $greg_date['day'];
}
else {
$year = isset($date['year']) ? intval($date['year']) : intval(date('Y'));
$month = isset($date['month']) ? intval($date['month']) : intval(date('n'));
$day = isset($date['day']) ? intval($date['day']) : intval(date('j'));
}
$hour = isset($date['hour']) ? intval($date['hour']) : intval(date('G'));
$minute = isset($date['minute']) ? intval($date['minute']) : intval(date('i'));
$second = isset($date['second']) ? intval($date['second']) : intval(date('s'));
$date = '@' . mktime($hour, $minute, $second, $month, $day, $year);
}
elseif ($date == NULL) {
$date = 'now';
}
// Why doesn't the freaking DateTime accept NULL az tz?!!
return isset($tz) ? new DateTime($date, $tz) : new DateTime($date);
}
/**
* Generates timestamp from given date.
*/
public static function getTimestamp($date) {
$date = self::ObjectFromDate($date);
return intval($date
->format('U'));
}
/**
* Determines wether PECL package php-intl is available or not.
*/
public static function hasINTL() {
return class_exists('IntlDateFormatter');
}
/**
* Returns non zero if given year is a leap year.
*
* Algorithm author Amin Saeedi <amin.w3dev@gmail.com>,
* Find him on github! @link http://github.org/amsa
*/
public static function isLeap($year_value) {
return array_search(($year_value + 2346) % 2820 % 128, array(
5,
9,
13,
17,
21,
25,
29,
34,
38,
42,
46,
50,
54,
58,
62,
67,
71,
75,
79,
83,
87,
91,
95,
100,
104,
108,
112,
116,
120,
124,
0,
));
}
/**
* Returns a valid timezone object from given timezone.
*
* Returns $tz itself if it is already a DateTimeZone object.
*/
public static function getTzObject($tz = NULL) {
if ($tz) {
if (is_string($tz)) {
$tz = new DateTimeZone($tz);
}
elseif (!$tz instanceof DateTimeZone) {
$tz = new DateTimeZone(date_default_timezone_get());
}
}
return $tz;
}
/**
* Returns a valid timezone string from given timezone.
*/
public static function getTzString($tz) {
$tz = self::getTzObject($tz);
return method_exists($tz, 'getName') ? $tz
->getName() : NULL;
}
/**
* Translates English numbers to Persian numbers and vice versa.
*
* @param bool $decorate
* If true, Returned string contains Persian numbers and if false, will
* contain English numbers.
*/
public static function decor($value, $decorate = FALSE) {
static $to_en = array(
'۱' => 1,
'۲' => 2,
'۳' => 3,
'۴' => 4,
'۵' => 5,
'۶' => 6,
'۷' => 7,
'۸' => 8,
'۹' => 9,
'۰' => 0,
);
static $to_fa = array(
1 => '۱',
2 => '۲',
3 => '۳',
4 => '۴',
5 => '۵',
6 => '۶',
7 => '۷',
8 => '۸',
9 => '۹',
0 => '۰',
);
return strtr($value, $decorate ? $to_fa : $to_en);
}
/**
* For extracting date from formatted date strings.
*/
public static function parser($date, $format) {
if (!(is_string($date) && is_string($format))) {
throw new Exception('Datex parser: date or format not valid.');
}
$granularities = array();
$j = $i = 0;
$format_len = strlen($format);
do {
while (!ctype_alpha($format[$i]) && $i < $format_len) {
$i++;
}
while (!ctype_digit($date[$j])) {
$j++;
}
switch ($format[$i]) {
case 'd':
$granularities['day'] = $date[$j] . $date[++$j];
break;
case 'j':
if (ctype_digit($date[$j + 1])) {
$granularities['day'] = $date[$j] . $date[++$j];
}
else {
$granularities['day'] = $date[$j];
}
break;
case 'm':
$granularities['month'] = $date[$j] . $date[++$j];
break;
case 'n':
if (ctype_digit($date[$j + 1])) {
$granularities['month'] = $date[$j] . $date[++$j];
}
else {
$granularities['month'] = $date[$j];
}
break;
case 'y':
case 'Y':
$granularities['year'] = $date[$j] . $date[++$j] . $date[++$j] . $date[++$j];
case 'h':
$granularities['hour'] = $date[$j] . $date[++$j];
break;
case 'g':
if (ctype_digit($date[$j + 1])) {
$granularities['hour'] = $date[$j] . $date[++$j];
}
else {
$granularities['hour'] = $date[$j];
}
break;
case 'H':
$granularities['hour'] = $date[$j] . $date[++$j];
break;
case 'G':
if (ctype_digit($date[$j + 1])) {
$granularities['hour'] = $date[$j] . $date[++$j];
}
else {
$granularities['hour'] = $date[$j];
}
break;
case 'i':
$granularities['minute'] = $date[$j] . $date[++$j];
break;
case 's':
$granularities['second'] = $date[$j] . $date[++$j];
break;
}
$j++;
} while (++$i < $format_len);
return $granularities;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DatexFormatter:: |
protected static | property | ||
DatexFormatter:: |
protected static | property | ||
DatexFormatter:: |
public static | function | Translates English numbers to Persian numbers and vice versa. | |
DatexFormatter:: |
public static | function | Similar to php date_format. | |
DatexFormatter:: |
public static | function | Formats a date according to format given. | |
DatexFormatter:: |
public static | function | Formats a date according to format given. | |
DatexFormatter:: |
public static | function | Generates timestamp from given date. | |
DatexFormatter:: |
public static | function | Returns a valid timezone object from given timezone. | |
DatexFormatter:: |
public static | function | Returns a valid timezone string from given timezone. | |
DatexFormatter:: |
public static | function | Determines wether PECL package php-intl is available or not. | |
DatexFormatter:: |
public static | function | Returns non zero if given year is a leap year. | |
DatexFormatter:: |
public static | function | Created a DateTime object containing date from $date. | |
DatexFormatter:: |
public static | function | For extracting date from formatted date strings. | |
DatexFormatter:: |
public static | function | Returns array containing names of days and monthes in persian. | |
DatexFormatter:: |
public static | function | Converts date format string (like 'Y-m-d') to it's PHP-Intl equivilant. | |
DatexFormatter:: |
public static | function | Converts a Jalali date to Gregorian. | |
DatexFormatter:: |
public static | function | Converts a Gregorian date to Jalali. |