Hi,

these is my contribution to implement islamic (hijri) calendar.

Waiting for your suggestions.



Without knowing the internals of the hijri calender here are a few generic
suggestions:

1) Consider using zend_parse_parameters rather than zend_get_parameters,
it'll help furture readability.

for suggestion 1 & 5 : the same code ans the same style of writing are used for the other calendars.


2) Rather than combining month/day/year into astring for returning from jdtohijri() consider returning them as an array of values, as string-OR-array depending on optional flag parameter, or return the component pieces by-ref.


i use that to keep the same syntax for result used with for the others calendars,
so the code must be reviewed in totality.


3) What's the maximum length of a hijri date string?  If it's 10 like the
gregorian calender MM/DD/YYYY, then you need to make your temporary buffer
be char[11] to hold the terminating NULL.

3a) When dealing with a short buffer it's a good idea to use snprintf() to
be absolutely certain you don't overrun.  Since you'll be estrdup()ing this
call (in RETURN_STRING()) later on anyway, you could just use spprintf()
here and pass the return in with a duplicate parameter of 0, but that's
splitting hairs.

3b) It'll also avoid an extra strlen() in RETURN_STRING() if you capture the
legnth output of sprintf() and pass it into RETURN_STRINGL().


ok, I replace sprintf by snprintf

4) To avoid potential namespace conflicts, it'd help to prefix the internal
methods you define in hijri.c with something uniqing (i.e.:
php_cal_hijri_SdnToHijri(), php_cal_hijri_HijriToSdn), or speicfy them as
'static' if they will only be used within their local object file.


I add the prefix to the internal methods defined in hijri.

5) Internal method names should be all lowercase with underscores used for
word boundaries. i.e.:  SdnToHijri => std_to_hijri.  studlyCaps is meant for
object method names exported to userspace.

6) How is Hijri pronounced? Is the j hard like english-"Jump", soft like
spanish-"Juego", or silent? Just curious on that one...


for more information about hijri calendar, please read islamic_calendar.txt

-Sara




Thank you.
                The Hijri (Islamic) Calender




The Islamic Calendar, used by Muslims world-wide, is a lunar one and 
consists of twelve months:

Muharram, Safar, Rabi` al-Awal, Rabi` al-Thaani, Jumaada al-Awal, 
Jumaada al-Thaani, Rajab, Sha`ban, Ramadan, Shawwal, Zul al-Qi`dah, 
Zul al-Hijjah.

An Islamic month runs from New Moon to New Moon.

The Islamic "New Year" is the 1st day of Muharram, and the years 
of the Islamic calender are dated from 1st Muharram, 1 A.H. 
which corresponds to July 16, 622 A.D. on the Gregorian solar calender 
currently used in Western nations. (Note: A.D. is mostly written 
C.E. - that is, Current Era). 

A.H. means "Anno Hegirae" - the Year of the Hijrah - and it was in 1 A.H. 
that the Prophet Muhammad migrated with his followers from Makkah
to what was to become the city of Madinah. This migration - Hijrah - 
is one the important events in the early history of Islam.

Because the Islamic calendar is lunar, the Hijri year is shorter than 
the Gregorian year by about 11 days. This also means that the Islamic
months are not "fixed" as the solar months of the Gregorian (Western)
calender are fixed to the cycle of the Seasons. Each year, the 
corresponding Islamic months falls 11 or so days "earlier"
compared to solar months.

The result is that the Islamic months can correspond to any (solar)
season with, for example, the month of Ramadan (the month of fasting)
falling in Spring, or Summer, or Autumn or Winter. It takes 33 years
for an Islamic month to correspond once again to the same solar month.

The exact beginning of every Islamic month cannot be calculated
exactly in advance, since it depends on an actual, and confirmed,
physical sighting of the new moon somewhere in the world. This means
that the Islamic calender corresponds to actual observed astronomical
events, and does not need to be adjusted, like the solar calender,
every fourth year (the leap year), or every four hundred years 
(the change from Julian to Gregorian) to account for variation 
between the Earth's seasonal changes and the variation in the 
Earth's orbit around the sun.


Muhammad Hussain Yusuf
Shawwal 1420 AH



diff -N -u -r source/php-4.3.8/ext/calendar/calendar.c 
compiled/php-4.3.8/ext/calendar/calendar.c
--- source/php-4.3.8/ext/calendar/calendar.c    2003-08-28 21:01:24.000000000 +0100
+++ compiled/php-4.3.8/ext/calendar/calendar.c  2004-08-04 16:58:18.000000000 +0100
@@ -44,6 +44,8 @@
        PHP_FE(jewishtojd, NULL)
        PHP_FE(jdtofrench, NULL)
        PHP_FE(frenchtojd, NULL)
+       PHP_FE(jdtohijri, NULL)
+       PHP_FE(hijritojd, NULL)
        PHP_FE(jddayofweek, NULL)
        PHP_FE(jdmonthname, NULL)
        PHP_FE(easter_date, NULL)
@@ -81,6 +83,7 @@
        CAL_JULIAN,
        CAL_JEWISH,
        CAL_FRENCH,
+       CAL_HIJRI,
        CAL_NUM_CALS
 };
 typedef long int (*cal_to_jd_func_t)(int month, int day, int year);
@@ -101,7 +104,8 @@
        { "Gregorian", "CAL_GREGORIAN", GregorianToSdn, SdnToGregorian, 12, 31, 
MonthNameShort, MonthNameLong },
        { "Julian", "CAL_JULIAN", JulianToSdn, SdnToJulian, 12, 31, MonthNameShort, 
MonthNameLong },
        { "Jewish", "CAL_JEWISH", JewishToSdn, SdnToJewish, 13, 30, JewishMonthName, 
JewishMonthName },
-       { "French", "CAL_FRENCH", FrenchToSdn, SdnToFrench, 13, 30, FrenchMonthName, 
FrenchMonthName }
+       { "French", "CAL_FRENCH", FrenchToSdn, SdnToFrench, 13, 30, FrenchMonthName, 
FrenchMonthName },
+       { "Hijri",  "CAL_HIJRI", HijriToSdn, SdnToHijri, 13, 30, HijriMonthName, 
HijriMonthName }
 };
 
 /* For jddayofweek */
@@ -109,7 +113,7 @@
 /* For jdmonthname */
 enum   { CAL_MONTH_GREGORIAN_SHORT, CAL_MONTH_GREGORIAN_LONG,
        CAL_MONTH_JULIAN_SHORT, CAL_MONTH_JULIAN_LONG, CAL_MONTH_JEWISH,
-       CAL_MONTH_FRENCH };
+       CAL_MONTH_FRENCH,CAL_MONTH_HIJRI };
 
 /* for heb_number_to_chars */
 static char alef_bet[25] = "0àلâمنهوçèéëىîًٌٍôِ÷ّùْ";
@@ -120,6 +124,7 @@
        REGISTER_LONG_CONSTANT("CAL_JULIAN", CAL_JULIAN, CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("CAL_JEWISH", CAL_JEWISH, CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("CAL_FRENCH", CAL_FRENCH, CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CAL_HIJRI",  CAL_HIJRI, CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("CAL_NUM_CALS", CAL_NUM_CALS, 
CONST_CS|CONST_PERSISTENT);
        /* constants for jddayofweek */
        REGISTER_LONG_CONSTANT("CAL_DOW_DAYNO", CAL_DOW_DAYNO, 
CONST_CS|CONST_PERSISTENT);
@@ -132,6 +137,7 @@
        REGISTER_LONG_CONSTANT("CAL_MONTH_JULIAN_LONG",         CAL_MONTH_JULIAN_LONG, 
CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("CAL_MONTH_JEWISH",                      
CAL_MONTH_JEWISH, CONST_CS|CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("CAL_MONTH_FRENCH",                      
CAL_MONTH_FRENCH, CONST_CS|CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CAL_MONTH_HIJRI",                       
CAL_MONTH_HIJRI, CONST_CS|CONST_PERSISTENT);
        /* constants for easter calculation */
        REGISTER_LONG_CONSTANT("CAL_EASTER_DEFAULT",                    
CAL_EASTER_DEFAULT, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("CAL_EASTER_ROMAN",                              
CAL_EASTER_ROMAN, CONST_CS | CONST_PERSISTENT);
@@ -300,7 +306,7 @@
 {
        pval **julday;
        int year, month, day;
-       char date[10];
+       char date[11];
 
        if (zend_get_parameters_ex(1, &julday) != SUCCESS) {
                WRONG_PARAM_COUNT;
@@ -557,6 +563,48 @@
 }
 /* }}} */
 
+/* {{{ proto string jdtohijri(int juliandaycount)
+   Converts a julian day count to a islamic(hijri) calendar date */
+PHP_FUNCTION(jdtohijri)
+{
+       pval **julday;
+       int year, month, day;
+       char date[12];
+
+       if (zend_get_parameters_ex(1, &julday) != SUCCESS) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long_ex(julday);
+       
+       SdnToHijri(Z_LVAL_PP(julday), &year, &month, &day);
+       /*sprintf(date, "%i/%i/%i", month, day, year);*/
+       snprintf(date,11,"%i/%i/%i", month, day, year);
+       RETURN_STRING(date, 1);
+}
+/* }}} */
+
+/* {{{ proto int hijritojd(int month, int day, int year)
+   Converts a islamic(hijri) calendar date to julian day count */
+PHP_FUNCTION(hijritojd)
+{
+       pval **year, **month, **day;
+       int jdate;
+
+       if (zend_get_parameters_ex(3, &month, &day, &year) != SUCCESS) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       convert_to_long_ex(month);
+       convert_to_long_ex(day);
+       convert_to_long_ex(year);
+
+       jdate = HijriToSdn(Z_LVAL_PP(year), Z_LVAL_PP(month), Z_LVAL_PP(day));
+
+       RETURN_LONG(jdate);
+}
+/* }}} */
+
 /* {{{ proto mixed jddayofweek(int juliandaycount [, int mode])
    Returns name or number of day of week from julian day count */
 PHP_FUNCTION(jddayofweek)
@@ -631,6 +679,10 @@
                        SdnToFrench(Z_LVAL_PP(julday), &year, &month, &day);
                        monthname = FrenchMonthName[month];
                        break;
+               case CAL_MONTH_HIJRI:                   /* hijri month */
+                       SdnToHijri(Z_LVAL_PP(julday), &year, &month, &day);
+                       monthname = HijriMonthName[month];
+                       break;
                default:                        /* default gregorian */
                case CAL_MONTH_GREGORIAN_SHORT:                 /* gregorian or julian 
month */
                        SdnToGregorian(Z_LVAL_PP(julday), &year, &month, &day);
diff -N -u -r source/php-4.3.8/ext/calendar/config.m4 
compiled/php-4.3.8/ext/calendar/config.m4
--- source/php-4.3.8/ext/calendar/config.m4     2002-03-12 17:10:56.000000000 +0100
+++ compiled/php-4.3.8/ext/calendar/config.m4   2004-07-20 15:18:09.000000000 +0100
@@ -7,5 +7,5 @@
 
 if test "$PHP_CALENDAR" = "yes"; then
   AC_DEFINE(HAVE_CALENDAR,1,[ ])
-  PHP_NEW_EXTENSION(calendar, calendar.c dow.c french.c gregor.c jewish.c julian.c 
easter.c cal_unix.c, $ext_shared)
+  PHP_NEW_EXTENSION(calendar, calendar.c dow.c french.c gregor.c jewish.c hijri.c 
julian.c easter.c cal_unix.c, $ext_shared)
 fi
diff -N -u -r source/php-4.3.8/ext/calendar/hijri.c 
compiled/php-4.3.8/ext/calendar/hijri.c
--- source/php-4.3.8/ext/calendar/hijri.c       1970-01-01 00:00:00.000000000 +0000
+++ compiled/php-4.3.8/ext/calendar/hijri.c     2004-08-04 15:53:28.000000000 +0100
@@ -0,0 +1,198 @@
+/* $selId: hijri.c,v 1.0 2004/07/20 14:50:00 lees Exp $
+ * Copyright 2004-2004, Mostapha ([EMAIL PROTECTED]), all rights reserved.
+ * Permission granted to use, copy, modify, distribute and sell so long as
+ * the above copyright and this permission statement are retained in all
+ * copies.  THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
+ *
+ * Based on :
+ * hconv.c
+ *
+ * Copyright (c) 1992 by Waleed A. Muhanna
+ *
+ * Send any comments/suggestions/fixes/additions to:
+ *             [EMAIL PROTECTED]
+ *
+ */
+
+#include <math.h>
+#include "sdncal.h"
+
+#define RPD     (0.01745329251994329577) /* radians per degree (pi/180) */
+
+
+char   *dow[7]= {
+       "Ahad", "Ithnain", "Zulatha", "Arbi'a",
+       "Khamees", "Jumma", "Sabt"
+};
+
+char  *HijriMonthName[13] = {"",
+       "Muharram", "Safar", "Rabi` al-Awal", "Rabi` al-Thaani",
+       "Jumaada al-Awal", "Jumaada al-Thaani", "Rajab", "Sha`ban",
+       "Ramadan", "Shawwal", "Zul al-Qi`dah", "Zul al-Hijjah"
+};
+
+char  *HijriMonthAraName[13] = {"",
+       "محرم", 
+       "صفر",
+       "ربيع الأول", 
+       "ربيع الثاني",
+       "جمادى الأول", 
+       "جمادى الثاني", 
+       "رجب",
+       "شعبان",
+       "رمضان",
+       "شوال",
+       "ذو القعدة",
+       "ذو الحجة"
+};
+
+
+/*
+ * Given an integer _n_ and a phase selector (nph=0,1,2,3 for
+ * new,first,full,last quarters respectively, function returns the
+ * Julian date/time of the Nth such phase since January 1900.
+ * Adapted from "Astronomical  Formulae for Calculators" by
+ * Jean Meeus, Third Edition, Willmann-Bell, 1985.
+ */
+double
+php_cal_hijri_tmoonphase( long n, int nph)
+{
+       double jd, t, t2, t3, k, ma, sa, tf, xtra;
+       k = n + nph/4.0;  t = k/1236.85;  t2 = t*t; t3 = t2*t;
+       jd =  2415020.75933 + 29.53058868*k - 1.178e-4 * t2
+           - 1.55e-7 * t3
+           + 3.3e-4 * sin (RPD * (166.56 +132.87*t -0.009173*t2));
+
+       /* Sun's mean anomaly */
+       sa =  RPD * (359.2242 + 29.10535608*k - 3.33e-5 * t2 - 3.47e-6 * t3);
+
+       /* Moon's mean anomaly */
+       ma =  RPD * (306.0253 + 385.81691806*k + 0.0107306*t2 +1.236e-5 *t3);
+
+       /* Moon's argument of latitude */
+       tf = RPD * 2.0 * (21.2964 + 390.67050646*k -0.0016528*t2
+                     -2.39e-6 * t3);
+
+       /* should reduce to interval 0-1.0 before calculating further */
+       if (nph==0 || nph==2)
+               /* Corrections for New and Full Moon */
+               xtra = (0.1734 - 0.000393*t) * sin(sa)
+                     +0.0021*sin(sa*2)
+                     -0.4068*sin(ma) +0.0161*sin(2*ma) -0.0004*sin(3*ma)
+                     +0.0104*sin(tf)
+                     -0.0051*sin(sa+ma) -0.0074*sin(sa-ma)
+                     +0.0004*sin(tf+sa) -0.0004*sin(tf-sa)
+                     -0.0006*sin(tf+ma) +0.0010*sin(tf-ma)
+                     +0.0005*sin(sa+ 2*ma);
+       else if (nph==1 || nph==3) {
+               xtra = (0.1721 - 0.0004*t) * sin(sa)
+                     +0.0021*sin(sa*2)
+                     -0.6280*sin(ma) +0.0089*sin(2*ma) -0.0004*sin(3*ma)
+                     +0.0079*sin(tf)
+                     -0.0119*sin(sa+ma) -0.0047*sin(sa-ma)
+                     +0.0003*sin(tf+sa) -0.0004*sin(tf-sa)
+                     -0.0006*sin(tf+ma) +0.0021*sin(tf-ma)
+                     +0.0003*sin(sa+ 2*ma) +0.0004*sin(sa-2*ma)
+                     -0.0003*sin(2*sa+ma);
+               if (nph==1)
+                       xtra = xtra +0.0028 -0.0004*cos(sa) +0.0003*cos(ma);
+               else
+                       xtra = xtra -0.0028 +0.0004*cos(sa) -0.0003*cos(ma);
+       } else {
+               printf("tmoonphase: illegal phase number\n");
+               exit(1);
+       }
+       /* convert from Ephemeris Time (ET) to (approximate)
+          Universal Time (UT) */
+       jd += xtra - (0.41 +1.2053*t +0.4992*t2)/1440;
+       return (jd);
+}
+
+
+/* parameters for Makkah: for a new moon to be visible after sunset on
+   a the same day in which it started, it has to have started before
+   (SUNSET-MINAGE)-TIMZ=3 A.M. local time. */
+
+#define TIMZ 3.0
+#define MINAGE 13.5
+#define SUNSET 19.5 /*approximate */
+#define TIMDIF (SUNSET-MINAGE)
+
+double
+php_cal_hijri_visible(long n, double *rjd)
+{
+       double jd;
+       float tf;
+       long d;
+
+       jd = php_cal_hijri_tmoonphase(n,0);  *rjd = jd;
+       d = jd;
+       tf = (jd - d);
+       if (tf<=0.5)  /*new moon starts in the afternoon */
+               return(jd+1.0); 
+       /* new moon starts before noon */
+       tf = (tf-0.5)*24 +TIMZ;  /* local time */ 
+       if (tf>TIMDIF) return(jd+1.0);  /*age at sunset < min for visiblity*/
+       return(jd);
+}
+
+
+/*
+ * Given a gregorian/julian date, compute corresponding Hijri date structure
+ * As a reference point, the routine uses the fact that the year
+ * 1405 A.H. started immediatly after lunar conjunction number 1048
+ * which occured on September 1984 25d 3h 10m UT.
+ */
+
+void SdnToHijri (
+                 long int sdn,
+                 int *pYear,
+                 int *pMonth,
+                 int *pDay)
+{
+       int hday,hmon,hyear,y,m,d;
+       double jd, mjd, rjd;
+       long k, hm;
+
+       jd = (double) sdn;
+       SdnToGregorian(sdn,&y,&m,&d);
+       /* obtain first approx. of how many new moons since the beginning
+          of the year 1900 */
+       k = 0.6 + (y + ((int) (m-0.5)) /12.0 + d/365.0 - 1900) *12.3685;
+       do  {mjd = php_cal_hijri_visible(k--, &rjd);} while (mjd>jd);  k++;
+       /*first of the month is the following day*/
+       hm = k -1048;
+       hyear = 1405 + (hm / 12);
+
+       hmon =  (hm % 12) +1;
+       if (hm !=0 && hmon<=0) {hmon +=12; hyear--; }
+       if (hyear<=0) hyear--;
+       *pDay = jd -mjd +1.0;
+       *pMonth = hmon;
+       *pYear =hyear;
+
+       return;
+}
+
+#define NMONTHS  (1405*12+1)
+
+/*
+ * Given a Hijri date, compute corresponding C.E. date structure
+ */
+
+long int HijriToSdn(
+                   int y,
+                   int m,
+                   int d)
+{
+       double jd, rjd;
+       long k;
+
+
+       if (y<0) y++;
+       k = m+ y*12 - NMONTHS;   /* # of months since 1/1/1405 */
+       jd = php_cal_hijri_visible(k+1048L, &rjd) +d;
+
+       return ((long int)jd);
+}
+
diff -N -u -r source/php-4.3.8/ext/calendar/php_calendar.h 
compiled/php-4.3.8/ext/calendar/php_calendar.h
--- source/php-4.3.8/ext/calendar/php_calendar.h        2002-05-12 16:06:04.000000000 
+0100
+++ compiled/php-4.3.8/ext/calendar/php_calendar.h      2004-07-20 14:27:35.000000000 
+0100
@@ -19,6 +19,8 @@
 PHP_FUNCTION(jewishtojd);
 PHP_FUNCTION(jdtofrench);
 PHP_FUNCTION(frenchtojd);
+PHP_FUNCTION(jdtohijri);
+PHP_FUNCTION(hijritojd);
 PHP_FUNCTION(jddayofweek);
 PHP_FUNCTION(jdmonthname);
 PHP_FUNCTION(easter_days);
diff -N -u -r source/php-4.3.8/ext/calendar/sdncal.h 
compiled/php-4.3.8/ext/calendar/sdncal.h
--- source/php-4.3.8/ext/calendar/sdncal.h      2002-10-31 10:16:23.000000000 +0100
+++ compiled/php-4.3.8/ext/calendar/sdncal.h    2004-07-20 14:56:55.000000000 +0100
@@ -86,8 +86,10 @@
 long int FrenchToSdn(int inputYear, int inputMonth, int inputDay);
 extern char *FrenchMonthName[14];
 
-/* Islamic calendar conversions. */
-/* Not implemented yet. */
+/* Islamic (Hijri) calendar conversions. */
+void SdnToHijri(long int sdn, int *pYear, int *pMonth, int *pDay);
+long int HijriToSdn(int inputYear, int inputMonth, int inputDay);
+extern char *HijriMonthName[13];
 
 /* Day of week conversion.  0=Sunday, 6=Saturday */
 int DayOfWeek(long int sdn);

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to