/************************************************************************ * $Id: umm_alqura.c,v 1.5 2004/07/16 01:16:32 nadim Exp $ * * ------------ * Description: * ------------ * Copyright (c) 2004, Arabeyes, Fayez Alhargan * * This is a program that computes the Hijary dates for Umm-AlQura * calendar the official calendar of the Kingdom of Saudi Arabia. * * King Abdulaziz City for Science and Technology * Computer and Electronics Research Institute * Riyadh, Saudi Arabia * alhargan-at-kacst.edu.sa * Tel:4813770 Fax:4813764 * * Fayez Alhargan version: opn1.2 * Fayez Alhargan last modified 22-1-2003 * * ----------------- * Revision Details: (Updated by Revision Control System) * ----------------- * $Date: 2004/07/16 01:16:32 $ * $Author: nadim $ * $Revision: 1.5 $ * $Source$ * * (www.arabeyes.org - under LGPL license - see COPYING file) ************************************************************************/</pre>
#include <stdlib.h> #include <math.h> #include "hijri.h" #define HStartYear 1420 #define HEndYear 1450 extern char *g_day[7]; extern char *h_day[7]; extern char *g_day_short[7]; extern char *h_day_short[7]; extern char *g_month[13]; extern char *h_month[13]; extern char *g_month_short[13]; extern char *h_month_short[13]; int MonthMap[]={19410, 19396,19337,19093,13613,13741,15210,18132,19913,19858,19110, 18774,12974,13677,13162,15189,19114,14669,13469,14685,12986, 13749,17834,15701,19098,14638,12910,13661,15066,18132,18085 }; /* makes it circular m[0]=m[12] & m[13]=m[1] */ short gmonth[14]={31,31,28,31,30,31,30,31,31,30,31,30,31,31}; /* makes it circular m[0]=m[12] & m[13]=m[1] */ short smonth[14]={31,30,30,30,30,30,29,31,31,31,31,31,31,30}; /* Various Prototypes */ int G2H(sDate *mydate, int dg, int mg, int yg); int H2G(sDate *mydate, int dh, int mh, int yh); int Hsub2G(sDate *mydate, int mh, int yh); double GCalendarToJD(int yg, int mg, double dg ); double JDToGCalendar(double JD, sDate *mydate); int GLeapYear(int year); void GDateAjust(sDate *mydate); int DayWeek(long JulianD); void JDToHCalendar(double JD, sDate *mydate); void JDToHACalendar(double JD, int *yh, int *mh, int *dh); double HCalendarToJD(int yh, int mh, int dh); double HCalendarToJDA(int yh, int mh, int dh); int HMonthLength(int yh, int mh); double ip(double x); int mod(double x, double y); int IsValid(int yh, int mh, int dh); /****************************************************************************/ /* Name: Hsub2G */ /* Type: Procedure */ /* Purpose: Finds Gdate(year,month,day) for Hdate(year,month,day) */ /* Arguments: */ /* Input: Hijri date: year:yh, month:mh */ /* Output: Gregorian date: year:yg, month:mg, day:dg , day of week:dayweek */ /* and returns flag found:1 not found:0 */ /****************************************************************************/ int Hsub2G(sDate *mydate, int mh, int yh) { int flag; long JD; double GJD; /* Make sure that the date is within the range of the tables */ if(mh < 1) {mh = 12;} if(mh > 12) {mh = 1;} if(yh < HStartYear) {yh = HStartYear;} if(yh > HEndYear) {yh = HEndYear;} GJD = HCalendarToJDA(yh, mh, 1); JDToGCalendar(GJD, mydate); JD = (long) GJD; mydate->weekday = (JD + 1) % 7; /* NOTE: so when is flag = 0 ? */ flag = 1; /* date has been found */ return(flag); } /****************************************************************************/ /* Name: HCalendarToJDA */ /* Type: Function */ /* Purpose: convert Hdate(year,month,day) to Exact Julian Day */ /* Arguments: */ /* Input : Hijrah date: year:yh, month:mh, day:dh */ /* Output: The Exact Julian Day: JD */ /****************************************************************************/ double HCalendarToJDA(int yh, int mh, int dh) { int flag, Dy, m, b; long JD; double GJD; /* estimate JD of the beginning of year */ JD = (long) HCalendarToJD(yh, 1, 1); Dy = MonthMap[yh-HStartYear]/4096; /* Mask 1111000000000000 */ GJD = JD - 3 + Dy; /* correct the JD value from stored tables */ b = MonthMap[yh - HStartYear]; b = b - Dy * 4096; for(m=1; m < mh; m++) { flag = b % 2; /* Mask for the current month */ if(flag) Dy = 30; else Dy = 29; GJD = GJD + Dy; /* Add the months lengths before mh */ b = (b - flag) / 2; } GJD = GJD + dh - 1; return(GJD); } /****************************************************************************/ /* Name: HMonthLength */ /* Type: Function */ /* Purpose: Obtains the month length */ /* Arguments: */ /* Input : Hijrah date: year:yh, month:mh */ /* Output: Month Length */ /****************************************************************************/ int HMonthLength(int yh, int mh) { int flag, Dy, m, b; if(yh<HStartYear || yh>HEndYear) { flag = 0; Dy = 0; } else { Dy = MonthMap[yh - HStartYear]/4096; /* Mask 1111000000000000 */ b = MonthMap[yh - HStartYear]; b = b - Dy * 4096; for(m=1; m <= mh; m++) { flag = b % 2; /* Mask for the current month */ if(flag) Dy = 30; else Dy = 29; b = (b - flag) / 2; } } return(Dy); } /****************************************************************************/ /* Name: DayInYear */ /* Type: Function */ /* Purpose: Obtains the day number in the yea */ /* Arguments: */ /* Input : Hijrah date: year:yh, month:mh day:dh */ /* Output: Day number in the Year */ /****************************************************************************/ int DayinYear(int yh, int mh, int dh) { int flag, Dy, m, b, DL; if(yh<HStartYear || yh>HEndYear) { flag = 0; DL = 0; } else { Dy = MonthMap[yh - HStartYear]/4096; /* Mask 1111000000000000 */ b = MonthMap[yh - HStartYear]; b = b - Dy * 4096; DL = 0; for(m = 1; m <= mh; m++) { flag = b % 2; /* Mask for the current month */ if(flag) Dy = 30; else Dy = 29; b = (b - flag) / 2; DL = DL + Dy; } DL = DL + dh; } return(DL); } /****************************************************************************/ /* Name: HYearLength */ /* Type: Function */ /* Purpose: Obtains the year length */ /* Arguments: */ /* Input : Hijrah date: year:yh */ /* Output: Year Length */ /****************************************************************************/ int HYearLength(int yh) { int flag, Dy, m, b, YL; if(yh<HStartYear || yh>HEndYear) { flag = 0; YL = 0; } else { Dy = MonthMap[yh - HStartYear]/4096; /* Mask 1111000000000000 */ b = MonthMap[yh - HStartYear]; b = b - Dy * 4096; flag = b % 2; /* Mask for the current month */ if(flag) YL = 30; else YL = 29; for(m = 2; m <= 12; m++) { flag = b % 2; /* Mask for the current month */ if(flag) Dy = 30; else Dy = 29; b = (b - flag) / 2; YL = YL + Dy; } } return(YL); } /****************************************************************************/ /* Name: G2H */ /* Type: Procedure */ /* Purpose: convert Gdate(year,month,day) to Hdate(year,month,day) */ /* Arguments: */ /* Input: Gregorian date: year:yg, month:mg, day:dg */ /* Output: Hijrah date: year:yh, month:mh, day:dh, day of week:dayweek */ /* and returns flag found:1 not found:0 */ /****************************************************************************/ int G2H(sDate *mydate, int dg, int mg, int yg) { int yh2, mh2; int df; int flag = 1; long J; double GJD, HJD; sDate tmpdate; sDate tmpdate2; int error_fill; GJD = GCalendarToJD(yg, mg, dg + 0.5); /* find JD of Gdate */ /* estimate the Hdate that correspond to the Gdate */ JDToHCalendar(GJD, &tmpdate); /* get the exact Julian Day */ HJD = HCalendarToJDA(tmpdate.year, tmpdate.month, tmpdate.day); df = (int) (GJD - HJD); tmpdate.day += df; while(tmpdate.day > 30) { tmpdate.day -= HMonthLength(tmpdate.year, tmpdate.month); tmpdate.month++; if(tmpdate.month > 12) { tmpdate.year++; tmpdate.month = 1; } } if(tmpdate.day == 30) { yh2 = tmpdate.year; mh2 = tmpdate.month + 1; if(mh2 > 12) { yh2++; mh2 = 1; } Hsub2G(&tmpdate2, mh2, yh2); /* Make sure that the month is 30days if not make adjustment */ if(dg == tmpdate2.day) { tmpdate.year = yh2; tmpdate.month = mh2; tmpdate.day = 1; } } J = (long) (GCalendarToJD(yg, mg, dg)+2); mydate->weekday = J % 7; mydate->to_numdays = 1; /* this needs to be fixed !! */ mydate->year = tmpdate.year; mydate->month = tmpdate.month; mydate->day = tmpdate.day; /* Fill-in the structure with various nicities a user might need */ error_fill = fill_datestruct(mydate, mydate->weekday, mg, mydate->month, g_day, g_day_short, g_month, g_month_short, h_day, h_day_short, h_month, h_month_short, NULL, 0); // h_events_table, sizeof(h_events_table)); return(flag); } /****************************************************************************/ /* Name: H2G */ /* Type: Procedure */ /* Purpose: convert Hdate(year,month,day) to Gdate(year,month,day) */ /* Arguments: */ /* Input/Ouput: Hijrah date: year:yh, month:mh, day:dh */ /* Output: Gregorian date: year:yg, month:mg, day:dg , day of week:dayweek */ /* and returns flag found:1 not found:0 */ /* Note: The function will correct Hdate if day=30 and the month is 29 only */ /****************************************************************************/ int H2G(sDate *mydate, int dh, int mh, int yh) { int found, yh1, mh1; int error_fill; sDate tmpdate; /* make sure values are within the allowed values */ if(dh > 30) { dh = 1; mh++; } if(dh < 1) { dh = 1; mh--; } if(mh > 12) { mh = 1; yh++; } if(mh < 1) { mh = 12; yh--; } /* find the date of the begining of the month */ found = Hsub2G(mydate, mh, yh); mydate->day += dh - 1; /* Make sure that dates are within the correct values */ GDateAjust(mydate); mydate->weekday += dh - 1; mydate->weekday = mydate->weekday % 7; /*find the date of the begining of the next month*/ if(dh == 30) { mh1 = mh + 1; yh1 = yh; if(mh1 > 12) {mh1 -= 12; yh1++;} found = Hsub2G(&tmpdate, mh1, yh1); /* Make sure that the month is 30days if not make adjustment */ if(mydate->day == tmpdate.day) { mydate->year = tmpdate.year; mydate->month = tmpdate.month; mydate->day = 1; } } /* Fill-in the structure with various nicities a user might need */ error_fill = fill_datestruct(mydate, mydate->weekday, mh, mydate->month, h_day, h_day_short, h_month, h_month_short, g_day, g_day_short, g_month, g_month_short, NULL, 0); // g_events_table, sizeof(g_events_table)); return(found); } /****************************************************************************/ /* Name: JDToGCalendar */ /* Type: Procedure */ /* Purpose: convert Julian Day to Gdate(year,month,day) */ /* Arguments: */ /* Input: The Julian Day: JD */ /* Output: Gregorian date: year:yy, month:mm, day:dd */ /****************************************************************************/ double JDToGCalendar(double JD, sDate *mydate) { double A, B, F; int alpha, C, E; long D, Z; Z = (long)floor (JD + 0.5); F = (JD + 0.5) - Z; alpha = (int)((Z - 1867216.25) / 36524.25); A = Z + 1 + alpha - alpha / 4; B = A + 1524; C = (int) ((B - 122.1) / 365.25); D = (long) (365.25 * C); E = (int)(((B - D) / 30.6001)); mydate->day =(int) (B - D - floor (30.6001 * E) + F); if (E < 14) mydate->month = E - 1; else mydate->month = E - 13; if (mydate->month > 2) mydate->year = C - 4716; else mydate->year = C - 4715; F = F * 24.0; return(F); } /****************************************************************************/ /* Name: GCalendarToJD */ /* Type: Function */ /* Purpose: convert Gdate(year,month,day) to Julian Day */ /* Arguments: */ /* Input : Gregorian date: year:yy, month:mm, day:dd */ /* Output: The Julian Day: JD */ /****************************************************************************/ double GCalendarToJD(int yy, int mm, double dd) { /* It does not take care of 1582 correction assumes correct calender from the past */ int A, B, m, y; double T1, T2, Tr; if (mm > 2) { y = yy; m = mm; } else { y = yy - 1; m = mm + 12; } A = y / 100; B = 2 - A + A / 4; T1=ip (365.25 * (y + 4716)); T2=ip (30.6001 * (m + 1)); Tr=T1+ T2 + dd + B - 1524.5 ; return(Tr); } /****************************************************************************/ /* Name: GLeapYear */ /* Type: Function */ /* Purpose: Determines if Gdate(year) is leap or not */ /* Arguments: */ /* Input : Gregorian date: year */ /* Output: 0:year not leap 1:year is leap */ /****************************************************************************/ int GLeapYear(int year) { int T = 0; if(year % 4 == 0) T = 1; /* leap_year = 1; */ if(year % 100 == 0) { /* years=100,200,300,500,... are not leap years */ T=0; /* years=400,800,1200,1600,2000,2400 are leap years */ if(year % 400 == 0) T = 1; } return(T); } /****************************************************************************/ /* Name: GDateAjust */ /* Type: Procedure */ /* Purpose: Adjust the G Dates by making sure that the month lengths */ /* are correct if not so take the extra days to next month or year */ /* Arguments: */ /* Input: Gregorian date: year:yg, month:mg, day:dg */ /* Output: corrected Gregorian date: year:yg, month:mg, day:dg */ /****************************************************************************/ void GDateAjust(sDate *mydate) { int dys; /* Make sure that dates are within the correct values */ /* Underflow */ if(mydate->month < 1) /* months underflow */ { /* plus as the underflow months is negative */ mydate->month += 12; mydate->year--; } if(mydate->day < 1) /* days underflow */ { /* month becomes the previous month */ mydate->month--; /* number of days of the month less the underflow days (it is plus as the sign of the day is negative) */ mydate->day += gmonth[mydate->month]; if(mydate->month == 2) mydate->day += GLeapYear(mydate->year); if(mydate->month < 1) /* months underflow */ { /* plus as the underflow months is negative */ mydate->month += 12; mydate->year--; } } /* Overflow */ if(mydate->month > 12) /* months */ { mydate->month -= 12; mydate->year++; } if(mydate->month == 2) /* number of days in the current month */ dys = gmonth[mydate->month] + GLeapYear(mydate->year); else dys = gmonth[mydate->month]; if(mydate->day > dys) /* days overflow */ { mydate->day -= dys; mydate->month++; if(mydate->month == 2) { /* number of days in the current month */ dys = gmonth[mydate->month] + GLeapYear(mydate->year); if(mydate->day > dys) { mydate->day -= dys; mydate->month++; } } if(mydate->month > 12) /* months */ { mydate->month -= 12; mydate->year++; } } mydate->to_numdays = dys; } /****************************************************************************/ /* The day of the week is obtained as Dy=(Julian+1)%7 Dy=0 Sunday Dy=1 Monday ... Dy=6 Saturday */ /****************************************************************************/ int DayWeek(long JulianD) { int Dy; Dy = (JulianD + 1) % 7; return(Dy); } /****************************************************************************/ /* Name: HCalendarToJD */ /* Type: Function */ /* Purpose: convert Hdate(year,month,day) to estimated Julian Day */ /* Arguments: */ /* Input : Hijrah date: year:yh, month:mh, day:dh */ /* Output: The Estimated Julian Day: JD */ /****************************************************************************/ double HCalendarToJD(int yh, int mh, int dh) { /* Estimating The JD for hijrah dates this is an approximate JD for the given hijrah date */ double md, yd; md = (mh - 1.0) * 29.530589; yd = (yh - 1.0) * 354.367068 + md + dh - 1.0; yd = yd + 1948439.0; /* add JD for 18/7/622 first Hijrah date */ return(yd); } /****************************************************************************/ /* Name: JDToHCalendar */ /* Type: Procedure */ /* Purpose: convert Julian Day to estimated Hdate(year,month,day) */ /* Arguments: */ /* Input: The Julian Day: JD */ /* Output : Hijrah date: year:yh, month:mh, day:dh */ /****************************************************************************/ void JDToHCalendar(double JD, sDate *mydate) { /* Estimating the hijrah date from JD */ double md, yd; yd = JD-1948439.0; /* subtract JD for 18/7/622 first Hijrah date*/ md = mod(yd, 354.367068); mydate->day = mod(md + 0.5, 29.530589)+1; mydate->month = (int) ((md/29.530589) + 1); yd = yd - md; mydate->year = (int) (yd/354.367068 + 1); if(mydate->day > 30) {mydate->day -= 30; mydate->month++;} if(mydate->month > 12) {mydate->month -= 12; mydate->year++;} } /****************************************************************************/ /* Name: JDToHACalendar */ /* Type: Procedure */ /* Purpose: convert Julian Day to Hdate(year,month,day) */ /* Arguments: */ /* Input: The Julian Day: JD */ /* Output : Hijrah date: year:yh, month:mh, day:dh */ /****************************************************************************/ void JDToHACalendar(double JD, int *yh, int *mh, int *dh) { int df; long J; double HJD; sDate tmpdate; /* Estimate the Hdate that correspond to the Gdate */ JDToHCalendar(JD, &tmpdate); /* get the exact Julian Day */ HJD = HCalendarToJDA(tmpdate.year, tmpdate.month, tmpdate.day); df = (int) (JD + 0.5 - HJD); tmpdate.day += df; while(tmpdate.day > 30) { tmpdate.day -= HMonthLength(tmpdate.year, tmpdate.month); tmpdate.month++; if(tmpdate.month > 12) { tmpdate.year++; tmpdate.month = 1; } } if(tmpdate.day == 30 && HMonthLength(tmpdate.year, tmpdate.month) < 30) { tmpdate.day = 1; tmpdate.month++; } if(tmpdate.month > 12) { tmpdate.month = 1; tmpdate.year++; } /* J = JD + 2; *dayweek = J % 7; */ *yh = tmpdate.year; *mh = tmpdate.month; *dh = tmpdate.day; } /**************************************************************************/ /* Purpose: return the integral part of a double value. */ /**************************************************************************/ double ip(double x) { double tmp; modf(x, &tmp); return(tmp); } /**************************************************************************/ /* Name: mod */ /* Purpose: The mod operation for doubles x mod y */ /**************************************************************************/ int mod(double x, double y) { int r; double d; d = x / y; r = (int) d; if(r < 0) r--; d = x - y * r; r = (int) d; return(r); } /**************************************************************************/ /* Purpose: returns 0 for incorrect Hijri date and 1 for correct date */ /**************************************************************************/ int IsValid(int yh, int mh, int dh) { int valid = 1; if((yh < HStartYear) || (yh > HEndYear)) valid = 0; if( (mh < 1) || (mh > 12)) valid = 0; if( (dh < 1) || (dh > HMonthLength(yh, mh)) ) valid = 0; return(valid); }
Iklan