This is hbcal.c in view mode; [Download] [Up]
/***************************************************************/ /* */ /* HBCAL.C */ /* */ /* Support for the Hebrew calendar */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992, 1993, 1994 by David F. Skoll. */ /* */ /* Derived from code written by Amos Shapir in 1978; revised */ /* 1985. */ /* */ /***************************************************************/ #include <stdio.h> /* For FILE used by protos.h - sigh. */ #include "config.h" #include "types.h" #include "protos.h" #include "globals.h" #include "err.h" #define HOUR 1080L #define DAY (24L*HOUR) #define WEEK (7L*DAY) #define M(h,p) ((long)(h*HOUR+p)) #define MONTH (DAY+M(12,793)) /* Correction to convert base reference to 1990. NOTE: If you change the value of BASE in config.h, this will NOT WORK! You'll have to add the appropriate number of days to CORRECTION. */ #define CORRECTION 732774L #define TISHREY 0 #define HESHVAN 1 #define KISLEV 2 #define TEVET 3 #define SHVAT 4 #define ADARA 5 #define ADARB 6 #define NISAN 7 #define IYAR 8 #define SIVAN 9 #define TAMUZ 10 #define AV 11 #define ELUL 12 #define ADAR 13 #define JAHR_NONE 0 #define JAHR_FORWARD 1 #define JAHR_BACKWARD 2 #define ADAR2ADARB 0 #define ADAR2ADARA 1 #define ADAR2BOTH 2 static char *HebMonthNames[] = { "Tishrey", "Heshvan", "Kislev", "Tevet", "Shvat", "Adar A", "Adar B", "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul", "Adar"}; static char MaxMonLen[] = { 30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29}; static char HebIsLeap[] = {0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1}; /***************************************************************/ /* */ /* RoshHashana */ /* */ /* Return the Julian date for Rosh Hashana of specified */ /* Hebrew year. (ie, 5751, not 1990) */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int RoshHashana(int i) #else int RoshHashana(i) int i; #endif { long j; j = DaysToHebYear(i-3744) - CORRECTION; return (int) j; /* No overflow check... very trusting! */ } /***************************************************************/ /* */ /* DaysToHebYear */ /* */ /* Return the number of days to RH of specified Hebrew year */ /* from new moon before Tishrey 1 5701. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC long DaysToHebYear(int y) #else long DaysToHebYear(y) int y; #endif { long m, nm, dw, s, l; l = y*7+1; /* no. of leap months */ m = y*12+l/19; /* total no. of months */ nm = m*MONTH+M(1,779); /* molad at 197 cycles */ s = m*28+nm/DAY-2; nm %= WEEK; l %= 19L; dw = nm/DAY; nm %= DAY; /* special cases of Molad Zaken */ if (nm >= 18*HOUR || (l < 12 && dw==3 && nm>=M(9,204)) || (l < 7 && dw==2 && nm>=M(15,589))) s++,dw++; /* ADU */ if(dw == 1 || dw == 4 || dw == 6) s++; return s; } /***************************************************************/ /* */ /* DaysInHebYear */ /* */ /* Return the number of days in the Hebrew year. */ /* */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DaysInHebYear(int y) #else int DaysInHebYear(y) int y; #endif { long thisyear, nextyear; thisyear = DaysToHebYear(y-3744); nextyear = DaysToHebYear(y-3743); return (int) (nextyear - thisyear); } /***************************************************************/ /* */ /* DaysInHebMonths */ /* */ /* Return a pointer to an array giving lengths of months */ /* given the LENGTH of the Hebrew year. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC char *DaysInHebMonths(int ylen) #else char *DaysInHebMonths(ylen) int ylen; #endif { static char monlen[13] = {30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29}; if (ylen > 355) { monlen[ADARA] = 30; ylen -= 30; } else monlen[ADARA] = 0; if (ylen == 353) monlen[KISLEV] = 29; else monlen[KISLEV] = 30; if (ylen == 355) monlen[HESHVAN] = 30; else monlen[HESHVAN] = 29; return monlen; } /***************************************************************/ /* */ /* HebToJul */ /* */ /* Convert a Hebrew date to Julian. */ /* Hebrew months range from 0-12, but Adar A has 0 length in */ /* non-leap-years. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int HebToJul(int hy, int hm, int hd) #else int HebToJul(hy, hm, hd) int hy, hm, hd; #endif { int ylen; char *monlens; int rh; int m; /* Do some range checking */ if (hy - 3761 < BASE || hy - 3760 > BASE+YR_RANGE) return -1; ylen = DaysInHebYear(hy); monlens = DaysInHebMonths(ylen); /* Get the Rosh Hashana of the year */ rh = RoshHashana(hy); /* Bump up to the appropriate month */ for (m=0; m<hm; m++) rh += monlens[m]; /* Add in appropriate number of days */ rh += hd - 1; return rh; } /***************************************************************/ /* */ /* JulToHeb */ /* */ /* Convert a Julian date to Hebrew. */ /* Hebrew months range from 0-12, but Adar A has 0 length in */ /* non-leap-years. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void JulToHeb(int jul, int *hy, int *hm, int *hd) #else void JulToHeb(jul, hy, hm, hd) int jul, *hy, *hm, *hd; #endif { int y, m, d; int rh; int ylen; char *monlen; /* Get the common year */ FromJulian(jul, &y, &m, &d); y += 3763; /* Over-estimate a bit to be on the safe side below... */ /* Find the RH just before desired date */ while ((rh=RoshHashana(y))>jul) y--; /* Got the year - now find the month */ jul -= rh; ylen = DaysInHebYear(y); monlen = DaysInHebMonths(ylen); m = 0; while((jul >= monlen[m]) || !monlen[m]) { jul -= monlen[m]; m++; } *hy = y; *hm = m; *hd = jul+1; } /***************************************************************/ /* */ /* HebNameToNum */ /* */ /* Convert a Hebrew month's name to its number, given the */ /* year. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int HebNameToNum(const char *mname) #else int HebNameToNum(mname) char *mname; #endif { int i; int m=-1; for (i=0; i<14; i++) if (!StrCmpi(mname, HebMonthNames[i])) { m = i; break; } return m; } /***************************************************************/ /* */ /* HebMonthname */ /* */ /* Convert a Hebrew month's number to its name, given the */ /* year. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC char *HebMonthName(int m, int y) #else char *HebMonthName(m, y) int m, y; #endif { if (m != ADARA && m != ADARB) return HebMonthNames[m]; if (!HebIsLeap[(y-1)%19]) return HebMonthNames[ADAR]; else return HebMonthNames[m]; } /***************************************************************/ /* */ /* GetValidHebDate */ /* */ /* Given the day of a month, a Hebrew month number, and a */ /* year, return a valid year number, month number, and day */ /* number. Returns 0 for success, non-0 for failure. */ /* If *dout is set to -1, then date is completely invalid. */ /* Otherwise, date is only invalid in specified year. */ /* */ /* Algorithm: */ /* - Convert references to Adar to Adar B. */ /* If jahr == 0 then */ /* - If no such date in current Hebrew year, return */ /* failure. */ /* else follow jahrzeit rules: */ /* - If jahr == 1: Convert 30 Kislev to 1 Tevet and */ /* 30 Heshvan to 1 Kislev if chaser. */ /* Convert 30 Adar A to 1 Nisan in nonleap */ /* This rule is NOT appropriate for a */ /* jahrzeit on 30 Adar A. Use rule 2 for */ /* that. However, I believe it is correct */ /* for smachot. */ /* - If jahr == 2: Convert 30 Kislev to 29 Kislev and */ /* 30 Heshvan to 29 Heshvan if chaser. */ /* Change 30 Adar A to 30 Shvat in nonleap */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int GetValidHebDate(int yin, int min, int din, int adarbehave, int *mout, int *dout, int jahr) #else int GetValidHebDate(yin, min, din, adarbehave, mout, dout, jahr) int yin, min, din, adarbehave, *mout, *dout, jahr; #endif { char *monlen; int ylen; *mout = min; *dout = din; /* Do some error checking */ if (din < 1 || din > MaxMonLen[min] || min < 0 || min > 13) { *dout = -1; return E_BAD_HEBDATE; } ylen = DaysInHebYear(yin); monlen = DaysInHebMonths(ylen); /* Convert ADAR as necessary */ if (min == ADAR) { switch(adarbehave) { case ADAR2ADARA: if (monlen[ADARA]) *mout = min = ADARA; else *mout = min = ADARB; break; case ADAR2ADARB: *mout = min = ADARB; break; default: Eprint("GetValidHebDate: Bad adarbehave value %d", adarbehave); return E_SWERR; } } if (din <= monlen[min]) return OK; switch(jahr) { case JAHR_NONE: return E_BAD_DATE; case JAHR_FORWARD: if (min == KISLEV) { *mout = TEVET; *dout = 1; return OK; } else if (min == HESHVAN) { *mout = KISLEV; *dout = 1; return OK; } else if (min == ADARA) { if (din > 29) { *dout = 1; *mout = NISAN; } else { *dout = din; *mout = ADARB; } return OK; } Eprint("GetValidHebDate: (1) software error! %d", jahr); return E_SWERR; case JAHR_BACKWARD: if (min == KISLEV) { *mout = KISLEV; *dout = 29; return OK; } else if (min == HESHVAN) { *mout = HESHVAN; *dout = 29; return OK; } else if (min == ADARA) { if (din > 29) { *dout = 30; *mout = SHVAT; } else { *mout = ADARB; *dout = din; } return OK; } Eprint("GetValidHebDate: (2) software error! %d", jahr); return E_SWERR; default: Eprint("GetValidHebDate: (3) software error! %d", jahr); return E_SWERR; } } /***************************************************************/ /* */ /* GetNextHebrewDate */ /* */ /* Get the next Hebrew date on or after specified date. */ /* */ /* Returns 0 for success, non-zero for failure. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int GetNextHebrewDate(int julstart, int hm, int hd, int jahr, int adarbehave, int *ans) #else int GetNextHebrewDate(julstart, hm, hd, jahr, adarbehave, ans) int julstart, hm, hd, jahr, adarbehave, *ans; #endif { int r, yout, mout, dout, jul=1; int adarflag = adarbehave; /* I initialize jul above to stop gcc from complaining about possible use of uninitialized variable. You can take it out if the small inefficiency really bothers you. */ /* If adarbehave == ADAR2BOTH, set adarflag to ADAR2ADARA for now */ if (adarbehave == ADAR2BOTH) adarflag = ADAR2ADARA; JulToHeb(julstart, &yout, &mout, &dout); r = 1; while(r) { r = GetValidHebDate(yout, hm, hd, adarflag, &mout, &dout, jahr); if (dout == -1) return r; if (r) { if (adarbehave == ADAR2BOTH && hm == ADAR) { if (adarflag == ADAR2ADARA) { adarflag = ADAR2ADARB; } else { adarflag = ADAR2ADARA; yout++; } } else yout++; continue; } jul = HebToJul(yout, mout, dout); if (jul < 0) return E_DATE_OVER; if (jul >= julstart) break; else { if (adarbehave == ADAR2BOTH && hm == ADAR) { if (adarflag == ADAR2ADARA) { adarflag = ADAR2ADARB; } else { adarflag = ADAR2ADARA; yout++; } } else yout++; r=1; /* Force loop to continue */ } } *ans = jul; return OK; } /***************************************************************/ /* */ /* ComputeJahr */ /* */ /* Given a date of death, compute the value to use for jahr. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ComputeJahr(int y, int m, int d, int *ans) #else int ComputeJahr(y, m, d, ans) int y, m, d, *ans; #endif { char *monlen; int len; *ans = JAHR_NONE; len = DaysInHebYear(y); monlen = DaysInHebMonths(len); /* Check for Adar A */ if (m == ADARA && monlen[m] == 0) { Eprint("No Adar A in %d", y); return E_BAD_HEBDATE; } if (d < 1 || d > MaxMonLen[m] || m < 0 || m > 13) { return E_BAD_HEBDATE; } if (d > monlen[m]) { Eprint("%d %s %d: %s", d, HebMonthNames[m], y, ErrMsg[E_BAD_HEBDATE]); return E_BAD_HEBDATE; } /* If the jahrzeit was in Adar A, we always use JAHR_BACKWARD */ if (m == ADARA) { *ans = JAHR_BACKWARD; return OK; } /* Get lengths of months in year following jahrzeit */ len = DaysInHebYear(y+1); monlen = DaysInHebMonths(len); if (d > monlen[m]) *ans = JAHR_FORWARD; else *ans = JAHR_BACKWARD; return OK; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.