Add support for pluggable calendars in Date API

Marat - April 5, 2008 - 10:24
Project:Date
Version:6.x-2.x-dev
Component:Date API
Category:feature request
Priority:normal
Assigned:Unassigned
Status:active
Description

Hi everyone,

In addition to the Gregorian calender, there are other calenders such as Hijri calenders (islamic calendar) and Chinese calendar (lunisolar calendar) and may more calenders existed.

I am interested to include the Hijri calender with this module if it is possible.

To convert Gregorian to Hijri, I may use this code:

<?php
// convert christian date to Istamic date
function chrToIsl($cday,$cmonth,$cyear) {
   
$d=$cday;
   
$m=$cmonth;
   
$y=$cyear;
                    if ((
$y>1582)||(($y==1582)&&($m>10))||(($y==1582)&&($m==10)&&($d>14)))
                        {
                       
$jd=(int)((1461*($y+4800+(int)(($m-14)/12)))/4)+(int)((367*($m-2-12*((int)(($m-14)/12))))/12)-
    (int)( (
3* ((int)(  ($y+4900+    (int)( ($m-14)/12)     )/100)    )   ) /4)+$d-32074;
                        }
                        else
                        {
                       
$jd = 367*$y-(int)((7*($y+5001+(int)(($m-9)/7)))/4)+(int)((275*$m)/9)+$d+1729777;
                        }
                   
$l=$jd-1948440+10632;
                   
$n=(int)(($l-1)/10631);
                   
$l=$l-10631*$n+353;
                   
$j=((int)((10985-$l)/5316))*((int)((50*$l)/17719))+((int)($l/5670))*((int)((43*$l)/15238));
                   
$l=$l-((int)((30-$j)/15))*((int)((17719*$j)/50))-((int)($j/16))*((int)((15238*$j)/43))+29 ;
                   
$m=(int)((24*$l)/709);
                   
$d=$l-(int)((709*$m)/24);
                   
$y=30*$n+$j-30;


return array(
$m,$d,$y);
}

//convert islamic to christian
function islToChr($hday,$hmonth,$hyear) {

   
$d=$hday;
   
$m=$hmonth;
   
$y=$hyear;
   
$jd=(int)((11*$y+3)/30)+354*$y+30*$m-(int)(($m-1)/2)+$d+1948440-385;
                    if (
$jd> 2299160 )
                        {
                        
$l=$jd+68569;
                        
$n=(int)((4*$l)/146097);
                       
$l=$l-(int)((146097*$n+3)/4);
                        
$i=(int)((4000*($l+1))/1461001);
                       
$l=$l-(int)((1461*$i)/4)+31;
                        
$j=(int)((80*$l)/2447);
                       
$d=$l-(int)((2447*$j)/80);
                       
$l=(int)($j/11);
                       
$m=$j+2-12*$l;
                       
$y=100*($n-49)+$i+l;
                        }
                    else
                        {
                        
$j=$jd+1402;
                        
$k=(int)(($j-1)/1461);
                        
$l=$j-1461*$k;
                        
$n=(int)(($l-1)/365)-(int)($l/1461);
                        
$i=$l-365*$n+30;
                       
$j=(int)((80*$i)/2447);
                       
$d=$i-(int)((2447*$j)/80);
                       
$i=(int)($j/11);
                       
$m=$j+2-12*$i;
                       
$y=4*$k+$n+$i-4716;
                        }
return array(
$d,$m,$y);
}
?>

Or I may use this code to use Arabic words for days and months:

<?php
 
function arabicDate($format, $timestamp) {
/*
  written by Salah Faya (<a href="mailto:visualmind@php.net" rel="nofollow">visualmind@php.net</a>) [url]http://www.php4arab.info/scripts/arabicDate[/url]
$format: [*]hj|ar|en:[jdl][Fmn][Yy][Aa]  (php.date function handles the rest chars)
  * will add <span dir=rtl lang=ar-sa>..</span>
  examples:
  echo arabicDate('hj:l d-F-Y هـ', time());  
  echo arabicDate('ar:l d/F - h:iA', time());
*/
$format=trim($format);
if (
substr($format,0,1)=='*') {
              
$use_span=true;
$format=substr($format,1);
       } else
$use_span=false;
$type=substr($format,0,3);

$arDay = array("Sat"=>"السبت", "Sun"=>"الأحد", "Mon"=>"الإثنين", "Tue"=>"الثلاثاء",
"Wed"=>"الأربعاء", "Thu"=>"الخميس", "Fri"=>"الجمعة");
$ampm=array('am'=>'صباحا','pm'=>'مساء');
list(
$d,$m,$y,$dayname,$monthname,$am)=explode(' ',date('d m Y D M a', $timestamp));
if (
$type=='hj:') {
if ((
$y>1582)||(($y==1582)&&($m>10))||(($y==1582)&&($m==10)&&($d>14))) {
$jd=ard_int((1461*($y+4800+ard_int(($m-14)/12)))/4);
$jd+=ard_int((367*($m-2-12*(ard_int(($m-14)/12))))/12);
$jd-=ard_int((3*(ard_int(($y+4900+ard_int(($m-14)/12))/100)))/4);
$jd+=$d-32075;
} else {
$jd = 367*$y-ard_int((7*($y+5001 + ard_int(($m-9)/7)))/4) + ard_int((275*$m)/9)+$d+1729777;
}
$l=$jd-1948440+10632;
$n=ard_int(($l-1)/10631);
$l=$l-10631*$n+355; // Correction: 355 instead of 354
$j=(ard_int((10985-$l)/5316)) * (ard_int((50*$l)/17719)) + (ard_int($l/5670)) * (ard_int((43*$l)/15238));
$l=$l-(ard_int((30-$j)/15)) * (ard_int((17719*$j)/50)) - (ard_int($j/16)) * (ard_int((15238*$j)/43))+29;
$m=ard_int((24*$l)/709);
$d=$l-ard_int((709*$m)/24);
$y=30*$n+$j-30;
$format=substr($format,3);
$hjMonth = array("محرم", "صفر", "ربيع أول", "ربيع ثاني",
"جماد أول", "جماد ثاني", "رجب", "شعبان", "رمضان", "شوال", "ذو القعدة", "ذو الحجة");
$format=str_replace('j', $d, $format);
$format=str_replace('d', str_pad($d,2,0,STR_PAD_LEFT), $format);
$format=str_replace('l', $arDay[$dayname], $format);
$format=str_replace('F', $hjMonth[$m-1], $format);
$format=str_replace('m', str_pad($m,2,0,STR_PAD_LEFT), $format);
$format=str_replace('n', $m, $format);
$format=str_replace('Y', $y, $format);
$format=str_replace('y', substr($y,2), $format);
$format=str_replace('a', substr($ampm[$am],0,1), $format);
$format=str_replace('A', $ampm[$am], $format);
} elseif (
$type=='ar:') {
$format=substr($format,3);
$arMonth=array("Jan"=>"يناير", "Feb"=>"فبراير","Mar"=>"مارس", "Apr"=>"ابريل", "May"=>"مايو",
"Jun"=>"يونيو", "Jul"=>"يوليو", "Aug"=>"اغسطس", "Sep"=>"سبتمبر", "Oct"=>"اكتوبر",
"Nov"=>"نوفمبر", "Dec"=>"ديسمبر");
$format=str_replace('l', $arDay[$dayname], $format);
$format=str_replace('F', $arMonth[$monthname], $format);
$format=str_replace('a', substr($ampm[$am],0,1), $format);
$format=str_replace('A', $ampm[$am], $format);
       }
$date = date($format, $timestamp);
if (
$use_span) return '<span dir="rtl" lang="ar-sa">'.$date.'</span>';
else return
$date;
}

function
ard_int($float) {
      return (
$float < -0.0000001) ? ceil($float-0.0000001) : floor($float+0.0000001); 
}  
?>

Any ideas how and where I should insert any of these code in the date module?

Thank you

#1

kbahey - April 5, 2008 - 13:17
Component:iCal API» Date API

I think a generalized pluggable "use your own calendar" as .inc would be a really good addition. This can be via a function like date_calendar_list() in settings, and checkboxes to enable the various calendars.

In case of Hijri, conversion as per the above code is provided, but it will not be accepted as, because of:
a) code style in not Drupal.
b) It is not pluggable.

#2

kbahey - April 7, 2008 - 22:11
Title:Is it possible to add this code to Date module (date converter)?» Add support for pluggable calendars in Date API

I am changing the title of this issue to make it more general. The Hijri calendar is just an instance of a calendar.

If we make calendars pluggable, then anyone can write their own.

The easiest instance is how to convert a given date from Gregorian to another calendar, which is what the above code provides.

An example of how to provide an API, is here, where you have a directory and in it, several .inc. An interface to select calendars from, and functions to convert between them.

So, this is more of a call for action for everyone, so we can have multiple calendars.

#3

KarenS - April 10, 2008 - 10:28

This is a big project that needs to be thought through. I started a wiki page in g.d.o. at http://groups.drupal.org/node/10607. Please add to that page anything that might be useful.

#4

davros - June 12, 2008 - 10:25

Marat
In the meantime, I've just used your code on a page to show Islamic date alongside Gregorian and it returned a day early - is that some kind of leap year effect?

Anyway, I thought this might also be useful for anyone wanting to use this with the month name instead of the number:
Just before the end of the chrToIsl function insert the following and change the return line

                 
                    //and get the month names in there
                    $months = array("Muharram", "Safar", "Rabia Awal", "Rabia Thani", "Jumaada Awal", "Jumaada Thani", "Rajab", "Sha'ban", "Ramadan", "Shawwal", "Dhul-Qi'dah", "Dhul-Hijjah");
$M = $months[$m-1];

return array($d,$M,$y);
}

Thanks

#5

KarenS - June 23, 2008 - 15:45
Version:5.x-2.x-dev» 6.x-2.x-dev

Moving D5 feature requests that aren't going to get into the initial official 5.2 release to be D6 feature requests that could potentially be backported to D5.2.

 
 

Drupal is a registered trademark of Dries Buytaert.