470 lines
10 KiB
C
470 lines
10 KiB
C
/* persian calendar functions original code is by Kees Couprie
|
|
http://www.geocities.com/couprie/calmath/ */
|
|
|
|
/* islamic conversion and moonphase calculation is taken from
|
|
*
|
|
* hdate
|
|
*
|
|
* Copyright (c) 1992 by Waleed A. Muhanna
|
|
*
|
|
* Permission for nonprofit use and redistribution of this software and
|
|
* its documentation is hereby granted without fee, provided that the
|
|
* above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation.
|
|
*
|
|
* No representation is made about the suitability of this software for any
|
|
* purpose. It is provided "as is" without express or implied warranty.
|
|
*
|
|
* Send any comments/suggestions/fixes/additions to:
|
|
* wmuhanna@magnus.acs.ohio-state.edu
|
|
*
|
|
*/
|
|
|
|
#include "calendarfunc.h"
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
long persian_jdn(struct icaltimetype dt)
|
|
{
|
|
const long PERSIAN_EPOCH = 1948321; /* The JDN of 1 Farvardin 1*/
|
|
int epbase;
|
|
long epyear;
|
|
long mdays;
|
|
long jdn;
|
|
epbase = dt.year - 474;
|
|
epyear = 474 + (epbase % 2820);
|
|
if (dt.month <= 7)
|
|
mdays = (dt.month - 1) * 31;
|
|
else
|
|
mdays = (dt.month - 1) * 30 + 6;
|
|
jdn = dt.day + mdays ;
|
|
jdn += (((epyear * 682) - 110) / 2816) ;
|
|
jdn += (epyear - 1) * 365;
|
|
jdn += (epbase / 2820) * 1029983 ;
|
|
jdn += (PERSIAN_EPOCH - 1);
|
|
return jdn;
|
|
}
|
|
|
|
double 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);
|
|
}
|
|
|
|
|
|
double visible(long n,double * rjd)
|
|
{
|
|
double jd;
|
|
float tf;
|
|
long d;
|
|
|
|
jd = 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);
|
|
}
|
|
|
|
|
|
struct icaltimetype jdn_islamic(long jdn)
|
|
{
|
|
struct icaltimetype h;
|
|
double mjd, rjd;
|
|
long k, hm;
|
|
|
|
/* obtain first approx. of how many new moons since the beginning
|
|
of the year 1900 */
|
|
h = jdn_civil(jdn);
|
|
k = 0.6 + (h.year + ((int) (h.month - 0.5)) / 12.0 + h.day
|
|
/ 365.0 - 1900) * 12.3685;
|
|
do{
|
|
mjd = visible(k--, &rjd);
|
|
} while (mjd > jdn);
|
|
k++;
|
|
/*first of the month is the following day*/
|
|
hm = k - 1048;
|
|
h.year = 1405 + (hm / 12);
|
|
|
|
h.month = (hm % 12) +1;
|
|
if (hm != 0 && h.month <= 0) {
|
|
h.month += 12;
|
|
h.year--;
|
|
}
|
|
if (h.year<=0)
|
|
h.year--;
|
|
h.day = jdn - mjd + 1;
|
|
|
|
return h;
|
|
}
|
|
|
|
|
|
long islamic_jdn(struct icaltimetype dt)
|
|
{
|
|
double jd, rjd;
|
|
long k;
|
|
|
|
k = dt.month + dt.year * 12 - NMONTHS; /* # of m since 1/1/1405 */
|
|
jd = visible(k + 1048L, &rjd) + dt.day;
|
|
return jd;
|
|
}
|
|
|
|
|
|
|
|
|
|
struct icaltimetype jdn_persian(long jdn)
|
|
{
|
|
struct icaltimetype ret, h;
|
|
int iYear, iMonth, iDay;
|
|
int depoch;
|
|
int cycle;
|
|
int cyear;
|
|
int ycycle;
|
|
int aux1, aux2;
|
|
int yday;
|
|
h.day = 1;
|
|
h.month = 1;
|
|
h.year = 475;
|
|
depoch = jdn - persian_jdn(h);
|
|
cycle = depoch / 1029983;
|
|
cyear = depoch % 1029983;
|
|
if( cyear == 1029982)
|
|
ycycle = 2820;
|
|
else{
|
|
aux1 = cyear / 366;
|
|
aux2 = cyear % 366;
|
|
ycycle = (((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) + aux1 + 1;
|
|
}
|
|
iYear = ycycle + (2820 * cycle) + 474;
|
|
if (iYear <= 0)
|
|
iYear = iYear - 1;
|
|
h.year = iYear;
|
|
yday = (jdn - persian_jdn(h)) + 1;
|
|
if(yday <= 186 )
|
|
iMonth = Ceil((yday-1) / 31);
|
|
else
|
|
iMonth = Ceil((yday - 7) / 30);
|
|
iMonth++;
|
|
h.month = iMonth;
|
|
iDay = (jdn - persian_jdn(h)) + 1;
|
|
ret.day = iDay;
|
|
ret.month = iMonth;
|
|
ret.year = iYear;
|
|
ret.is_date = 1;
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
int Ceil(float number)
|
|
{
|
|
int ret;
|
|
if(number>0)
|
|
number += 0.5;
|
|
ret = number;
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
long civil_jdn(struct icaltimetype dt)
|
|
{
|
|
long jdn = ((1461 * (dt.year + 4800 + ((dt.month - 14) / 12))) / 4)
|
|
+ ((367 * (dt.month - 2 - 12 * (((dt.month - 14) / 12)))) / 12)
|
|
- ((3 * (((dt.year + 4900 + ((dt.month - 14) / 12)) / 100))) / 4)
|
|
+ dt.day - 32075;
|
|
return jdn;
|
|
}
|
|
|
|
|
|
|
|
struct icaltimetype jdn_civil(long jdn)
|
|
{
|
|
long l, n, i, j;
|
|
struct icaltimetype ret;
|
|
int iday, imonth, iyear;
|
|
l = jdn + 68569;
|
|
n = ((4 * l) / 146097);
|
|
l = l - ((146097 * n + 3) / 4);
|
|
i = ((4000 * (l + 1)) / 1461001);
|
|
l = l - ((1461 * i) / 4) + 31;
|
|
j = ((80 * l) / 2447);
|
|
iday = l - ((2447 * j) / 80);
|
|
l = (j / 11);
|
|
imonth = j + 2 - 12 * l;
|
|
iyear = 100 * (n - 49) + i + l;
|
|
ret.day = iday;
|
|
ret.month = imonth;
|
|
ret.year = iyear;
|
|
ret.hour = 0;
|
|
ret.minute = 0;
|
|
ret.second = 0;
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
struct icaltimetype civil_persian(struct icaltimetype dt)
|
|
{
|
|
return(jdn_persian(civil_jdn(dt)));
|
|
}
|
|
|
|
|
|
struct icaltimetype civil_islamic(struct icaltimetype dt)
|
|
{
|
|
return(jdn_islamic(civil_jdn(dt)));
|
|
}
|
|
|
|
|
|
|
|
struct icaltimetype persian_civil(struct icaltimetype dt)
|
|
{
|
|
return(jdn_civil(persian_jdn(dt)));
|
|
}
|
|
|
|
|
|
struct icaltimetype islamic_civil(struct icaltimetype dt)
|
|
{
|
|
return(jdn_civil(islamic_jdn(dt)));
|
|
}
|
|
|
|
struct icaltimetype get_civil(struct icaltimetype dt, int calendar){
|
|
if(calendar == 0)
|
|
return dt;
|
|
else if(calendar == 1)
|
|
return persian_civil(dt);
|
|
else if(calendar == 2)
|
|
return islamic_civil(dt);
|
|
|
|
}
|
|
|
|
|
|
int isPersianLeap(int year)
|
|
{
|
|
struct icaltimetype dt, dold;
|
|
|
|
dt.year = year;
|
|
dt.month = 12;
|
|
dt.day = 30;
|
|
dold = jdn_civil(2453108);
|
|
dt = civil_persian(persian_civil(dt));
|
|
if(dt.day == 1)
|
|
return 0;
|
|
return 1 ;
|
|
}
|
|
|
|
int isGregorianLeap(int year)
|
|
{
|
|
if(year % 4 !=0)
|
|
return 0;
|
|
if(year % 100 == 0 && year % 400 != 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int days_in_month(int month, int year, int calendar)
|
|
{
|
|
if(calendar == 0)
|
|
return days_in_gregorian_month(month, year);
|
|
else if(calendar == 1)
|
|
return days_in_persian_month(month, year);
|
|
else if(calendar == 2)
|
|
return days_in_islamic_month(month, year);
|
|
}
|
|
|
|
|
|
|
|
int days_in_persian_month(int month, int year)
|
|
{
|
|
if(month < 7)
|
|
return 31;
|
|
if(month < 12)
|
|
return 30;
|
|
if(isPersianLeap(year))
|
|
return 30;
|
|
return 29;
|
|
}
|
|
|
|
|
|
int days_in_islamic_month(int month, int year)
|
|
{
|
|
struct icaltimetype dt, dold;
|
|
month++;
|
|
if(month == 13){
|
|
month = 1;
|
|
year++;
|
|
}
|
|
dt.year = year;
|
|
dt.month = month;
|
|
dt.day = 1;
|
|
dt = jdn_islamic(islamic_jdn(dt) - 1);
|
|
return dt.day;
|
|
|
|
}
|
|
|
|
int days_in_gregorian_month(int month, int year)
|
|
{
|
|
switch(month){
|
|
case 4:
|
|
case 6:
|
|
case 9:
|
|
case 11:
|
|
return 30;
|
|
case 2:
|
|
return 28 + isGregorianLeap(year);
|
|
default:
|
|
return 31;
|
|
}
|
|
}
|
|
|
|
int day_of_week(struct icaltimetype dt)
|
|
{
|
|
int jd;
|
|
jd = civil_jdn(dt);
|
|
jd --;
|
|
return jd % 7;
|
|
}
|
|
|
|
int moon(struct icaltimetype h)
|
|
{
|
|
int k, jd, i ,j, jdn;
|
|
long mjd = 0;
|
|
jd = civil_jdn(h);
|
|
if(datemoon[jd%200][1] == jd)
|
|
return datemoon[jd%200][0];
|
|
|
|
k = 1 + (h.year + ((int) (h.month - 0.5)) / 12.0 + h.day / 365.0 - 1900) * 12.3685;
|
|
do {
|
|
mjd = tmoonphase(k--, 0);
|
|
} while (mjd > jd);
|
|
|
|
k--;
|
|
|
|
for(i = tmoonphase(k,0); i < tmoonphase(k+5,0 ); i++){
|
|
datemoon[i%200][0] = 0;
|
|
datemoon[i%200][1] = i;
|
|
}
|
|
|
|
for(j = 0; j < 6; j++){
|
|
for(i = 0; i < 4; i++){
|
|
mjd = tmoonphase(k, i);
|
|
datemoon[mjd%200][0] = i+1;
|
|
datemoon[mjd%200][1] = mjd;
|
|
}
|
|
k++;
|
|
}
|
|
|
|
if(datemoon[jd%200][1] == jd)
|
|
return datemoon[jd%200][0];
|
|
return 0;
|
|
}
|
|
|
|
|
|
int daysComp(struct icaltimetype d1, struct icaltimetype d2){
|
|
if(d1.year < d2.year)
|
|
return 1; /* d1 < d2 */
|
|
if(d1.year > d2.year)
|
|
return 2; /* d1 > d2 */
|
|
|
|
/* years are equal */
|
|
if(d1.month < d2.month)
|
|
return 1; /* d1 < d2 */
|
|
if(d1.month > d2.month)
|
|
return 2; /* d1 > d2 */
|
|
|
|
/* months are equal */
|
|
if(d1.day < d2.day)
|
|
return 1; /* d1 < d2 */
|
|
if(d1.day > d2.day)
|
|
return 2; /* d1 > d2 */
|
|
|
|
return 0; /* days are equal */
|
|
}
|
|
|
|
|
|
int daysEqual(struct icaltimetype d1, struct icaltimetype d2){
|
|
if(daysComp(d1, d2) == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int daysLater(struct icaltimetype d1, struct icaltimetype d2){
|
|
if(daysComp(d1, d2) == 1)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int daysEarlier(struct icaltimetype d1, struct icaltimetype d2){
|
|
if(daysComp(d1, d2) == 2)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int daysLaterEqual(struct icaltimetype d1, struct icaltimetype d2){
|
|
if(daysComp(d1, d2) != 2)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int daysEarlierEqual(struct icaltimetype d1, struct icaltimetype d2){
|
|
if(daysComp(d1, d2) != 1)
|
|
return 1;
|
|
return 0;
|
|
}
|