calendar_jalali.module in Calendar Systems 6.2
Implements necessary hooks & helpers to support Jalali Calendar.
File
calendars/calendar_jalali/calendar_jalali.moduleView source
<?php
/**
* @file
* Implements necessary hooks & helpers to support Jalali Calendar.
*/
/**
* Implements hook_calendar_info().
*
* @ingroup hook_implementation
*/
function calendar_jalali_calendar_info() {
$calendar = array();
// An array of calendar information,
// keyed by the calendar identifier.
$calendar['jalali'] = array(
// Calendar name:
'name' => t('Jalali (Solar Hijri)'),
// Administration form callback:
'config callback' => 'calendar_jalali_admin_form',
// Date formatter callback:
'format callback' => 'calendar_jalali_formatter',
// Calendar convert callbacks:
'convert callbacks' => array(
'from gregorian' => 'calendar_jalali_convert',
'to gregorian' => 'calendar_jalali_convert_reverse',
),
// Callback calendar month days:
'month days callback' => 'calendar_jalali_month_days',
);
return $calendar;
}
/**
* Form callback for Jalali calendar administration.
*
* @param $config
* Calendar specific config options.
*
* @ingroup forms
*/
function calendar_jalali_admin_form($config) {
$form = array();
$locale = function_exists('locale') ? TRUE : FALSE;
$form['calendar_jalali_translate_numbers'] = array(
'#type' => 'checkbox',
'#title' => t('Use the Persian representaion of numbers in date strings.'),
'#description' => t('e.g. Use !number-fa instead of <strong>!number-en</strong>.', array(
'!number-fa' => '۹',
'!number-en' => '9',
)),
'#default_value' => $config['calendar_jalali_translate_numbers'],
'#return_value' => 1,
);
$form['translate_options'] = array(
'#type' => 'fieldset',
'#title' => t('Calendar Translation Settings'),
'#description' => t('You need to have the <em>Locale</em> module enabled to make use of these options.'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['translate_options']['calendar_jalali_translate_meridiem'] = array(
'#type' => 'checkbox',
'#title' => t('Translate Ante/Post meridiems regardless of site language.'),
'#description' => t('If checked, you also need to translate Ante/Post meridiem to Persian using the <a href="!link">translate interface</a>.', array(
'!link' => url('admin/build/translate'),
)),
'#default_value' => !$locale ? 0 : $config['calendar_jalali_translate_meridiem'],
'#return_value' => 1,
'#disabled' => !$locale,
);
$form['translate_options']['calendar_jalali_translate_weekdays'] = array(
'#type' => 'checkbox',
'#title' => t('Translate weekdays and show Persian representations regardless of site language.'),
'#description' => t('If checked, you also need to translate weekday names to Persian using the <a href="!link">translate interface</a>.', array(
'!link' => url('admin/build/translate'),
)),
'#default_value' => !$locale ? 0 : $config['calendar_jalali_translate_weekdays'],
'#return_value' => 1,
'#disabled' => !$locale,
);
$form['translate_options']['calendar_jalali_translate_months'] = array(
'#type' => 'checkbox',
'#title' => t('Translate month names and show Persian representations regardless of site language.'),
'#description' => t('If checked, you also need to translate month names to Persian using the <a href="!link">translate interface</a>.', array(
'!link' => url('admin/build/translate'),
)),
'#default_value' => !$locale ? 0 : $config['calendar_jalali_translate_months'],
'#return_value' => 1,
'#disabled' => !$locale,
);
return $form;
}
/**
* Jalali calendar date converter callback.
*
* Converts Gregorian to Jalali.
*
* @param $year
* Gregorian year.
* @param $month
* Gregorian month.
* @param $day
* Gregorian day.
*
* @return
* An array of Jalali date elements.
* - year: Jalali year.
* - month: Jalali month.
* - day: Jalali day.
*
* @ingroup calendar_convert_callback
*/
function calendar_jalali_convert($year, $month, $day) {
$day = $day - 1;
$month = $month - 1;
$year = $year - 1600;
$jmonth_days = calendar_jalali_month_days();
$gmonth_days = calendar_gregorian_month_days();
$gday_no = 365 * $year + (int) (($year + 3) / 4) - (int) (($year + 99) / 100) + (int) (($year + 399) / 400);
for ($i = 0; $i < $month; ++$i) {
$gday_no += $gmonth_days[$i];
}
// Leap year / After february.
if ($month > 1 && ($year % 4 == 0 && $year % 100 != 0 || $year % 400 == 0)) {
++$gday_no;
}
$gday_no += $day;
$jday_no = $gday_no - 79;
$j_np = (int) ($jday_no / 12053);
$jday_no %= 12053;
$jyear = 979 + 33 * $j_np + 4 * (int) ($jday_no / 1461);
$jday_no %= 1461;
if ($jday_no >= 366) {
$jyear += (int) (($jday_no - 1) / 365);
$jday_no = ($jday_no - 1) % 365;
}
for ($i = 0; $i < 11 && $jday_no >= $jmonth_days[$i]; ++$i) {
$jday_no -= $jmonth_days[$i];
}
return array(
$jyear,
$i + 1,
$jday_no + 1,
);
}
/**
* Jalali calendar reverse date converter callback.
*
* Converts Jalali to Gregorian.
*
* @param $year
* Jalali year.
* @param $month
* Jalali month.
* @param $day
* Jalali day.
*
* @return
* An array of Gregorian date elements.
* - year: Gregorian year.
* - month: Gregorian month.
* - day: Gregorian day.
*
* @ingroup calendar_convert_callback
*/
function calendar_jalali_convert_reverse($year, $month, $day) {
$day = $day - 1;
$month = $month - 1;
$year = $year - 979;
$jmonth_days = calendar_jalali_month_days();
$gmonth_days = calendar_gregorian_month_days();
$jday_no = 365 * $year + (int) ($year / 33) * 8 + (int) (($year % 33 + 3) / 4);
for ($i = 0; $i < $month; ++$i) {
$jday_no += $jmonth_days[$i];
}
$jday_no += $day;
$gday_no = $jday_no + 79;
$gyear = 1600 + 400 * (int) ($gday_no / 146097);
$gday_no = $gday_no % 146097;
$leap = TRUE;
if ($gday_no >= 36525) {
$gday_no--;
$gyear += 100 * (int) ($gday_no / 36524);
$gday_no = $gday_no % 36524;
if ($gday_no >= 365) {
$gday_no++;
}
else {
$leap = FALSE;
}
}
$gyear += 4 * (int) ($gday_no / 1461);
$gday_no %= 1461;
if ($gday_no >= 366) {
$leap = FALSE;
$gday_no--;
$gyear += (int) ($gday_no / 365);
$gday_no = $gday_no % 365;
}
for ($i = 0; $gday_no >= $gmonth_days[$i] + ($i == 1 && $leap); $i++) {
$gday_no -= $gmonth_days[$i] + ($i == 1 && $leap);
}
return array(
$gyear,
$i + 1,
$gday_no + 1,
);
}
/**
* Jalali calendar date formatter callback.
*
* {Calendar conversion is a just a pain!}
*
* @param $timestamp
* Unix timestamp to be formatted.
* The proper $timezone value has been added by Drupal format_date().
* @param $format
* PHP date() function format string.
* @param $timezone
* Time zone offset in seconds.
* @param $langcode
* Optional language code to translate to a language other than the default.
* @param $calendar
* A copy of calendar information.
*
* @return
* The formatted date or FALSE otherwise.
*
* @see format_date()
*
* @ingroup calendar_format_callback
*/
function calendar_jalali_formatter($timestamp, $format, $timezone = 0, $langcode = NULL, $calendar = NULL) {
$date = '';
list($year, $month, $day) = explode('~', calendar_systems_formatter($timestamp, 'Y~n~j'));
list($jyear, $jmonth, $jday) = calendar_jalali_convert($year, $month, $day);
$max = strlen($format);
for ($i = 0; $i < $max; $i++) {
switch ($format[$i]) {
case 'y':
$date .= substr($jyear, 2, 4);
break;
case 'Y':
$date .= $jyear;
break;
case 'M':
case 'F':
// Check configs for month representation.
$function = $calendar['config']['calendar_jalali_translate_months'] ? 'array_values' : 'array_keys';
$jmonths = $function(_calendar_jalali_t('months'));
$date .= $jmonths[$jmonth - 1];
break;
case 'D':
case 'l':
$function = $calendar['config']['calendar_jalali_translate_weekdays'] ? 'array_values' : 'array_keys';
$weekdays = $function(_calendar_jalali_t('weekdays'));
$date .= $weekdays[calendar_jalali_formatter($timestamp, 'w')];
break;
case 'a':
case 'A':
$default = calendar_systems_formatter($timestamp, $format[$i]);
if ($calendar['config']['calendar_jalali_translate_meridiem']) {
$case = $format[$i] == 'a' ? 'lower' : 'upper';
$meridiems = _calendar_jalali_t('meridiem_' . $case);
$date .= $meridiems[$default];
}
else {
$date .= $default;
}
break;
case 'm':
$date .= sprintf('%02d', $jmonth);
break;
case 'n':
$date .= $jmonth;
break;
case 'd':
$date .= sprintf('%02d', $jday);
break;
case 'j':
$date .= $jday;
break;
case 'w':
$date .= (calendar_systems_formatter($timestamp, 'w') + 1) % 7;
break;
case 'r':
$date .= calendar_jalali_formatter($timestamp, 'D, d M Y H:i:s O', $timezone, NULL, $calendar);
break;
case 'N':
$date .= calendar_jalali_formatter($timestamp, 'w') + 1;
break;
case 't':
$jmonth_days = calendar_jalali_month_days();
if ($jmonth < 12) {
$date .= $jmonth_days[$jmonth - 1];
}
elseif (_calendar_jalali_check($jyear, $jmonth, 30)) {
$date .= '30';
}
else {
$date .= '29';
}
break;
case 'z':
$day_of_year = 0;
$jmonth_days = calendar_jalali_month_days();
for ($n = 0; $n < $jmonth - 1; $n++) {
$day_of_year += $jmonth_days[$n];
}
$day_of_year += $jday - 1;
$date .= $day_of_year;
break;
case 'L':
$date .= _calendar_jalali_check($jyear, 12, 30) ? '1' : '0';
break;
case 'W':
$zone = calendar_jalali_formatter($timestamp, 'z');
// First saturday.
$saturday = ($zone - calendar_jalali_formatter($timestamp, 'w') + 7) % 7;
$days = $zone - $saturday;
if ($days < 0) {
$zone += _calendar_jalali_check($jyear - 1, 12, 30) ? 366 : 365;
$saturday = ($zone - calendar_jalali_formatter($timestamp, 'w') + 7) % 7;
$days = $zone - $saturday;
}
$date .= floor($days / 7) + 1;
break;
case '\\':
if ($i + 1 < strlen($format)) {
$date .= $format[++$i];
}
else {
$date .= $format[$i];
}
break;
default:
$date .= calendar_systems_formatter($timestamp, $format[$i], $timezone);
}
}
// Check configs for number representation.
if ($calendar['config']['calendar_jalali_translate_numbers']) {
return _calendar_jalali_convert_number($date);
}
return $date;
}
/**
* Helper function to check whether the combination
* of passed values are in Jalali calendar range or not.
*
* @param $year
* Jalali year.
* @param $month
* Jalali month.
* @param $day
* Jalali day.
*
* @return
* Boolean value.
*/
function _calendar_jalali_check($year, $month, $day) {
$jmonth_days = calendar_jalali_month_days();
if ($year < 0 || $year > 32767 || $month < 1 || $month > 12 || $day < 1) {
return FALSE;
}
if ($day > $jmonth_days[$month - 1] + ($month == 12 && !(($year - 979) % 33 % 4))) {
return FALSE;
}
return TRUE;
}
/**
* Helper function to convert a
* Latin number to its Persian representaion.
*
* @param $string
* The haystack string to be googled!
*
* @return
* Number-Persianized string!
*/
function _calendar_jalali_convert_number($string) {
$output = '';
$max = strlen(trim($string));
for ($i = 0; $i < $max; ++$i) {
$output .= ctype_digit($string[$i]) ? pack('C*', 0xdb, 0xb0 + $string[$i]) : $string[$i];
}
return $output;
}
/**
* Calendar month days helper.
*
* @return
* An array of ordered numbers corresponding
* to a Jalali year months length of days.
*
* @ingroup calendar_helper
*/
function calendar_jalali_month_days() {
return array(
31,
31,
31,
31,
31,
31,
30,
30,
30,
30,
30,
29,
);
}
/**
* Calendar translate helper.
*
* @param $type
* Type of needed translation.
* - weekdays
* - months
* - meridiem_lower
* - meridiem_upper
* @param $destination
* Imply the destination string:
* - source
* - translation
*
* @return
* An associative array of translations keyed by their sources.
*
* @ingroup calendar_helper
*/
function _calendar_jalali_t($type, $destination = 'translation') {
if ($destination == 'translation' && !function_exists('locale')) {
$destination = 'source';
}
$source = array(
'weekdays' => array(
'Shanbeh',
'Yekshanbeh',
'Doshanbeh',
'Sehshanbeh',
'Chaharshanbeh',
'Panjshanbeh',
'Jomeh',
),
'months' => array(
'Farvardin',
'Ordibehesht',
'Khordad',
'Tir',
'Mordad',
'Shahrivar',
'Mehr',
'Aban',
'Azar',
'Dey',
'Bahman',
'Esfand',
),
'meridiem_lower' => array(
'am',
'pm',
),
'meridiem_upper' => array(
'AM',
'PM',
),
);
return $destination == 'source' ? $source[$type] : array_combine($source[$type], array_map('locale', $source[$type], array_fill(0, count($source[$type]), 'fa')));
}
/**
* Calendar translate dummy.
*
* @ingroup calendar_helper
* @see http://api.drupal.org/api/drupal/includes--common.inc/function/t/6
*/
function _calendar_jalali_potx($type = 'all', $destination = 'translation') {
$dummy = array(
t('am'),
t('pm'),
t('AM'),
t('PM'),
t('Shanbeh'),
t('Yekshanbeh'),
t('Doshanbeh'),
t('Sehshanbeh'),
t('Chaharshanbeh'),
t('Panjshanbeh'),
t('Jomeh'),
t('Farvardin'),
t('Ordibehesht'),
t('Khordad'),
t('Tir'),
t('Mordad'),
t('Shahrivar'),
t('Mehr'),
t('Aban'),
t('Azar'),
t('Dey'),
t('Bahman'),
t('Esfand'),
);
}
Functions
Name | Description |
---|---|
calendar_jalali_admin_form | Form callback for Jalali calendar administration. |
calendar_jalali_calendar_info | Implements hook_calendar_info(). |
calendar_jalali_convert | Jalali calendar date converter callback. |
calendar_jalali_convert_reverse | Jalali calendar reverse date converter callback. |
calendar_jalali_formatter | Jalali calendar date formatter callback. |
calendar_jalali_month_days | Calendar month days helper. |
_calendar_jalali_check | Helper function to check whether the combination of passed values are in Jalali calendar range or not. |
_calendar_jalali_convert_number | Helper function to convert a Latin number to its Persian representaion. |
_calendar_jalali_potx | Calendar translate dummy. |
_calendar_jalali_t | Calendar translate helper. |