home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / remind-03.00.19.tgz / remind-03.00.19.tar / remind-03.00.19 / src / hbcal.c < prev    next >
C/C++ Source or Header  |  1998-02-09  |  17KB  |  545 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  HBCAL.C                                                    */
  4. /*                                                             */
  5. /*  Support for the Hebrew calendar                            */
  6. /*                                                             */
  7. /*  This file is part of REMIND.                               */
  8. /*  Copyright (C) 1992-1998 by David F. Skoll                  */
  9. /*                                                             */
  10. /*  Derived from code written by Amos Shapir in 1978; revised  */
  11. /*  1985.                                                      */
  12. /*                                                             */
  13. /***************************************************************/
  14.  
  15. #include "config.h"
  16. static char const RCSID[] = "$Id: hbcal.c,v 1.2 1998/02/10 03:15:51 dfs Exp $";
  17.  
  18. #include <stdio.h>  /* For FILE used by protos.h - sigh. */
  19. #include "types.h"
  20. #include "protos.h"
  21. #include "globals.h"
  22. #include "err.h"
  23. #define HOUR 1080L
  24. #define DAY  (24L*HOUR)
  25. #define WEEK (7L*DAY)
  26. #define M(h,p) ((long)(h*HOUR+p))
  27. #define MONTH (DAY+M(12,793))
  28.  
  29. /* Correction to convert base reference to 1990.  NOTE:  If you change
  30.    the value of BASE in config.h, this will NOT WORK!  You'll have to
  31.    add the appropriate number of days to CORRECTION. */
  32.  
  33. #define CORRECTION 732774L
  34.  
  35. #define TISHREY 0
  36. #define HESHVAN 1
  37. #define KISLEV  2
  38. #define TEVET   3
  39. #define SHVAT   4
  40. #define ADARA   5
  41. #define ADARB   6
  42. #define NISAN   7
  43. #define IYAR    8
  44. #define SIVAN   9
  45. #define TAMUZ  10
  46. #define AV     11
  47. #define ELUL   12
  48. #define ADAR   13
  49.  
  50. #define JAHR_NONE     0
  51. #define JAHR_FORWARD  1
  52. #define JAHR_BACKWARD 2
  53.  
  54. #define ADAR2ADARB 0
  55. #define ADAR2ADARA 1
  56. #define ADAR2BOTH  2
  57.  
  58. static char *HebMonthNames[] = {
  59.     "Tishrey", "Heshvan", "Kislev", "Tevet", "Shvat", "Adar A", "Adar B",
  60.     "Nisan", "Iyar", "Sivan", "Tamuz", "Av", "Elul", "Adar"};
  61.  
  62. static char MaxMonLen[] = {
  63.     30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29};
  64.  
  65. static char HebIsLeap[] = {0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1};
  66.   
  67. /***************************************************************/
  68. /*                                                             */
  69. /*  RoshHashana                                                */
  70. /*                                                             */
  71. /*  Return the Julian date for Rosh Hashana of specified       */
  72. /*  Hebrew year.  (ie, 5751, not 1990)                         */
  73. /*                                                             */
  74. /***************************************************************/
  75. #ifdef HAVE_PROTOS
  76. PUBLIC int RoshHashana(int i)
  77. #else
  78. int RoshHashana(i)
  79. int i;
  80. #endif     
  81. {
  82.     long j;
  83.     j = DaysToHebYear(i-3744) - CORRECTION;
  84.     return (int) j; /* No overflow check... very trusting! */
  85. }
  86.  
  87. /***************************************************************/
  88. /*                                                             */
  89. /*  DaysToHebYear                                              */
  90. /*                                                             */
  91. /*  Return the number of days to RH of specified Hebrew year   */
  92. /*  from new moon before Tishrey 1 5701.                       */
  93. /*                                                             */
  94. /***************************************************************/
  95. #ifdef HAVE_PROTOS
  96. PUBLIC long DaysToHebYear(int y)
  97. #else
  98. long DaysToHebYear(y)
  99. int y;
  100. #endif
  101. {
  102.     long m, nm, dw, s, l;
  103.  
  104.     l = y*7+1;      /* no. of leap months */
  105.     m = y*12+l/19;  /* total no. of months */
  106.     nm = m*MONTH+M(1,779); /* molad at 197 cycles */
  107.     s = m*28+nm/DAY-2;
  108.  
  109.     nm %= WEEK;
  110.     l %= 19L;
  111.     dw = nm/DAY;
  112.     nm %= DAY;
  113.  
  114.     /* special cases of Molad Zaken */
  115.     if (nm >= 18*HOUR ||
  116.     (l < 12 && dw==3 && nm>=M(9,204)) ||
  117.     (l <  7 && dw==2 && nm>=M(15,589)))
  118.     s++,dw++;
  119.     /* ADU */
  120.     if(dw == 1 || dw == 4 || dw == 6)
  121.     s++;
  122.     return s;
  123. }
  124.  
  125. /***************************************************************/
  126. /*                                                             */
  127. /*  DaysInHebYear                                              */
  128. /*                                                             */
  129. /*  Return the number of days in the Hebrew year.              */
  130. /*                                                             */
  131. /*                                                             */
  132. /***************************************************************/
  133. #ifdef HAVE_PROTOS
  134. PUBLIC int DaysInHebYear(int y)
  135. #else
  136. int DaysInHebYear(y)
  137. int y;
  138. #endif
  139. {
  140.     long thisyear, nextyear;
  141.  
  142.     thisyear = DaysToHebYear(y-3744);
  143.     nextyear = DaysToHebYear(y-3743);
  144.     return (int) (nextyear - thisyear);
  145. }
  146.  
  147. /***************************************************************/
  148. /*                                                             */
  149. /*  DaysInHebMonths                                            */
  150. /*                                                             */
  151. /*  Return a pointer to an array giving lengths of months      */
  152. /*  given the LENGTH of the Hebrew year.                       */
  153. /*                                                             */
  154. /***************************************************************/
  155. #ifdef HAVE_PROTOS
  156. PUBLIC char *DaysInHebMonths(int ylen)
  157. #else
  158. char *DaysInHebMonths(ylen)
  159. int ylen;
  160. #endif
  161. {
  162.     static char monlen[13] =
  163.     {30, 29, 30, 29, 30, 0, 29, 30, 29, 30, 29, 30, 29};
  164.  
  165.  
  166.     if (ylen > 355) {
  167.     monlen[ADARA] = 30;
  168.     ylen -= 30;
  169.     } else monlen[ADARA] = 0;
  170.  
  171.     if (ylen == 353) monlen[KISLEV] = 29; else monlen[KISLEV] = 30;
  172.     if (ylen == 355) monlen[HESHVAN] = 30; else monlen[HESHVAN] = 29;
  173.  
  174.     return monlen;
  175. }
  176.  
  177. /***************************************************************/
  178. /*                                                             */
  179. /*  HebToJul                                                   */
  180. /*                                                             */
  181. /*  Convert a Hebrew date to Julian.                           */
  182. /*  Hebrew months range from 0-12, but Adar A has 0 length in  */
  183. /*  non-leap-years.                                            */
  184. /*                                                             */
  185. /***************************************************************/
  186. #ifdef HAVE_PROTOS
  187. PUBLIC int HebToJul(int hy, int hm, int hd)
  188. #else
  189. int HebToJul(hy, hm, hd)
  190. int hy, hm, hd;
  191. #endif
  192. {
  193.     int ylen;
  194.     char *monlens;
  195.     int rh;
  196.     int m;
  197.  
  198.     /* Do some range checking */
  199.     if (hy - 3761 < BASE || hy - 3760 > BASE+YR_RANGE) return -1;
  200.  
  201.     ylen = DaysInHebYear(hy);
  202.     monlens = DaysInHebMonths(ylen);
  203.  
  204.     /* Get the Rosh Hashana of the year */
  205.     rh = RoshHashana(hy);
  206.  
  207.     /* Bump up to the appropriate month */
  208.     for (m=0; m<hm; m++) rh += monlens[m];
  209.  
  210.     /* Add in appropriate number of days */
  211.     rh += hd - 1;
  212.     return rh;
  213. }
  214.  
  215. /***************************************************************/
  216. /*                                                             */
  217. /*  JulToHeb                                                   */
  218. /*                                                             */
  219. /*  Convert a Julian date to Hebrew.                           */
  220. /*  Hebrew months range from 0-12, but Adar A has 0 length in  */
  221. /*  non-leap-years.                                            */
  222. /*                                                             */
  223. /***************************************************************/
  224. #ifdef HAVE_PROTOS
  225. PUBLIC void JulToHeb(int jul, int *hy, int *hm, int *hd)
  226. #else
  227. void JulToHeb(jul, hy, hm, hd)
  228. int jul, *hy, *hm, *hd;
  229. #endif
  230. {
  231.     int y, m, d;
  232.     int rh;
  233.     int ylen;
  234.     char *monlen;
  235.     /* Get the common year */
  236.     FromJulian(jul, &y, &m, &d);
  237.     y += 3763; /* Over-estimate a bit to be on the safe side below... */
  238.  
  239.     /* Find the RH just before desired date */
  240.     while ((rh=RoshHashana(y))>jul) y--;
  241.  
  242.     /* Got the year - now find the month */
  243.     jul -= rh;
  244.     ylen = DaysInHebYear(y);
  245.     monlen = DaysInHebMonths(ylen);
  246.     m = 0;
  247.     while((jul >= monlen[m]) || !monlen[m]) {
  248.     jul -= monlen[m];
  249.     m++;
  250.     }
  251.  
  252.     *hy = y;
  253.     *hm = m;
  254.     *hd = jul+1;
  255. }
  256.  
  257. /***************************************************************/
  258. /*                                                             */
  259. /*  HebNameToNum                                               */
  260. /*                                                             */
  261. /*  Convert a Hebrew month's name to its number, given the     */
  262. /*  year.                                                      */
  263. /*                                                             */
  264. /***************************************************************/
  265. #ifdef HAVE_PROTOS
  266. PUBLIC int HebNameToNum(const char *mname)
  267. #else
  268. int HebNameToNum(mname)
  269. char *mname;
  270. #endif
  271. {
  272.     int i;
  273.     int m=-1;
  274.  
  275.     for (i=0; i<14; i++)
  276.     if (!StrCmpi(mname, HebMonthNames[i])) {
  277.         m = i;
  278.         break;
  279.     }
  280.  
  281.     return m;
  282. }   
  283.  
  284. /***************************************************************/
  285. /*                                                             */
  286. /*  HebMonthname                                               */
  287. /*                                                             */
  288. /*  Convert a Hebrew month's number to its name, given the     */
  289. /*  year.                                                      */
  290. /*                                                             */
  291. /***************************************************************/
  292. #ifdef HAVE_PROTOS
  293. PUBLIC char *HebMonthName(int m, int y)
  294. #else
  295. char *HebMonthName(m, y)
  296. int m, y;
  297. #endif
  298. {
  299.     if (m != ADARA && m != ADARB) return HebMonthNames[m];
  300.  
  301.     if (!HebIsLeap[(y-1)%19]) return HebMonthNames[ADAR];
  302.     else return HebMonthNames[m];
  303. }
  304.  
  305. /***************************************************************/
  306. /*                                                             */
  307. /* GetValidHebDate                                             */
  308. /*                                                             */
  309. /* Given the day of a month, a Hebrew month number, and a      */
  310. /* year, return a valid year number, month number, and day     */
  311. /* number.  Returns 0 for success, non-0 for failure.          */
  312. /* If *dout is set to -1, then date is completely invalid.     */
  313. /* Otherwise, date is only invalid in specified year.          */
  314. /*                                                             */
  315. /* Algorithm:                                                  */
  316. /* - Convert references to Adar to Adar B.                     */
  317. /* If jahr == 0 then                                           */ 
  318. /*     - If no such date in current Hebrew year, return        */
  319. /*       failure.                                              */
  320. /* else follow jahrzeit rules:                                 */
  321. /*     - If jahr == 1: Convert 30 Kislev to 1 Tevet and        */
  322. /*                     30 Heshvan to 1 Kislev if chaser.       */
  323. /*                     Convert 30 Adar A to 1 Nisan in nonleap */
  324. /*                     This rule is NOT appropriate for a      */
  325. /*                     jahrzeit on 30 Adar A.  Use rule 2 for  */
  326. /*                     that.  However, I believe it is correct */
  327. /*                     for smachot.                            */
  328. /*     - If jahr == 2: Convert 30 Kislev to 29 Kislev and      */
  329. /*                     30 Heshvan to 29 Heshvan if chaser.     */
  330. /*                     Change 30 Adar A to 30 Shvat in nonleap */
  331. /*                                                             */
  332. /***************************************************************/
  333. #ifdef HAVE_PROTOS
  334. PUBLIC int GetValidHebDate(int yin, int min, int din, int adarbehave,
  335.                            int *mout, int *dout, int jahr)
  336. #else
  337. int GetValidHebDate(yin, min, din, adarbehave, mout, dout, jahr)
  338. int yin, min, din, adarbehave, *mout, *dout, jahr;
  339. #endif
  340. {
  341.     char *monlen;
  342.     int ylen;
  343.  
  344.     *mout = min;
  345.     *dout = din;
  346.  
  347.     /* Do some error checking */
  348.     if (din < 1 || din > MaxMonLen[min] || min < 0 || min > 13) {
  349.     *dout = -1;
  350.     return E_BAD_HEBDATE;
  351.     }
  352.  
  353.     ylen = DaysInHebYear(yin);
  354.     monlen = DaysInHebMonths(ylen);
  355.  
  356.     /* Convert ADAR as necessary */
  357.     if (min == ADAR) {
  358.     switch(adarbehave) {
  359.     case ADAR2ADARA: if (monlen[ADARA]) *mout = min = ADARA;
  360.     else             *mout = min = ADARB;
  361.     break;
  362.  
  363.     case ADAR2ADARB: *mout = min = ADARB; break;
  364.  
  365.     default:
  366.         Eprint("GetValidHebDate: Bad adarbehave value %d", adarbehave);
  367.         return E_SWERR;
  368.     }
  369.     }
  370.  
  371.     if (din <= monlen[min]) return OK;
  372.  
  373.     switch(jahr) {
  374.     case JAHR_NONE: return E_BAD_DATE;
  375.  
  376.     case JAHR_FORWARD:
  377.     if (min == KISLEV) {
  378.             *mout = TEVET;
  379.             *dout = 1;
  380.             return OK;
  381.     } else if (min == HESHVAN) {
  382.             *mout = KISLEV;
  383.             *dout = 1;
  384.             return OK;
  385.     } else if (min == ADARA) {
  386.             if (din > 29) {
  387.         *dout = 1;
  388.         *mout = NISAN;
  389.             } else {
  390.         *dout = din;
  391.         *mout = ADARB;
  392.             }
  393.         return OK;
  394.     }
  395.  
  396.     Eprint("GetValidHebDate: (1) software error! %d", jahr);
  397.     return E_SWERR;
  398.  
  399.     case JAHR_BACKWARD:
  400.     if (min == KISLEV) {
  401.             *mout = KISLEV;
  402.             *dout = 29;
  403.             return OK;
  404.     } else if (min == HESHVAN) {
  405.             *mout = HESHVAN;
  406.             *dout = 29;
  407.             return OK;
  408.     } else if (min == ADARA) {
  409.         if (din > 29) {
  410.         *dout = 30;
  411.         *mout = SHVAT;
  412.             } else {
  413.         *mout = ADARB;
  414.         *dout = din;
  415.             }
  416.         return OK;
  417.     }
  418.  
  419.     Eprint("GetValidHebDate: (2) software error! %d", jahr);
  420.     return E_SWERR;
  421.  
  422.     default:
  423.     Eprint("GetValidHebDate: (3) software error! %d", jahr);
  424.     return E_SWERR;
  425.     }
  426. }
  427.  
  428.  
  429. /***************************************************************/
  430. /*                                                             */
  431. /*  GetNextHebrewDate                                          */
  432. /*                                                             */
  433. /*  Get the next Hebrew date on or after specified date.       */
  434. /*                                                             */
  435. /*  Returns 0 for success, non-zero for failure.               */
  436. /*                                                             */
  437. /***************************************************************/
  438. #ifdef HAVE_PROTOS
  439. PUBLIC int GetNextHebrewDate(int julstart, int hm, int hd,
  440.                  int jahr, int adarbehave, int *ans)
  441. #else
  442. int GetNextHebrewDate(julstart, hm, hd, jahr, adarbehave, ans)
  443. int julstart, hm, hd, jahr, adarbehave, *ans;
  444. #endif
  445. {
  446.     int r, yout, mout, dout, jul=1;
  447.     int adarflag = adarbehave;
  448.  
  449.     /* I initialize jul above to stop gcc from complaining about
  450.        possible use of uninitialized variable.  You can take it
  451.        out if the small inefficiency really bothers you. */
  452.  
  453.     /* If adarbehave == ADAR2BOTH, set adarflag to ADAR2ADARA for now */
  454.     if (adarbehave == ADAR2BOTH) adarflag = ADAR2ADARA;
  455.  
  456.     JulToHeb(julstart, &yout, &mout, &dout);
  457.  
  458.     r = 1;
  459.     while(r) {
  460.     r = GetValidHebDate(yout, hm, hd, adarflag, &mout, &dout, jahr);
  461.     if (dout == -1) return r;
  462.     if (r) {
  463.         if (adarbehave == ADAR2BOTH && hm == ADAR) {
  464.         if (adarflag == ADAR2ADARA) {
  465.             adarflag = ADAR2ADARB;
  466.         } else {
  467.             adarflag = ADAR2ADARA;
  468.             yout++;
  469.         }
  470.         } else yout++;
  471.         continue;
  472.     }
  473.     jul = HebToJul(yout, mout, dout);
  474.     if (jul < 0) return E_DATE_OVER;
  475.     if (jul >= julstart) break;
  476.     else {
  477.         if (adarbehave == ADAR2BOTH && hm == ADAR) {
  478.         if (adarflag == ADAR2ADARA) {
  479.             adarflag = ADAR2ADARB;
  480.         } else {
  481.             adarflag = ADAR2ADARA;
  482.             yout++;
  483.         }
  484.         } else yout++;
  485.         r=1;  /* Force loop to continue */
  486.     }
  487.     }
  488.     *ans = jul;
  489.     return OK;
  490. }
  491.  
  492. /***************************************************************/
  493. /*                                                             */
  494. /*  ComputeJahr                                                */
  495. /*                                                             */
  496. /*  Given a date of death, compute the value to use for jahr.  */
  497. /*                                                             */
  498. /***************************************************************/
  499. #ifdef HAVE_PROTOS
  500. PUBLIC int ComputeJahr(int y, int m, int d, int *ans)
  501. #else
  502. int ComputeJahr(y, m, d, ans)
  503. int y, m, d, *ans;
  504. #endif
  505. {
  506.     char *monlen;
  507.     int len;
  508.  
  509.     *ans = JAHR_NONE;
  510.  
  511.     len = DaysInHebYear(y);
  512.     monlen = DaysInHebMonths(len);
  513.  
  514. /* Check for Adar A */
  515.     if (m == ADARA && monlen[m] == 0) {
  516.     Eprint("No Adar A in %d", y);
  517.     return E_BAD_HEBDATE;
  518.     }
  519.  
  520.  
  521.     if (d < 1 || d > MaxMonLen[m] || m < 0 || m > 13) {
  522.     return E_BAD_HEBDATE;
  523.     }
  524.  
  525.     if (d > monlen[m]) {
  526.     Eprint("%d %s %d: %s", d, HebMonthNames[m], y, ErrMsg[E_BAD_HEBDATE]);
  527.     return E_BAD_HEBDATE;
  528.     }
  529.  
  530. /* If the jahrzeit was in Adar A, we always use JAHR_BACKWARD */
  531.     if (m == ADARA) {
  532.     *ans = JAHR_BACKWARD;
  533.     return OK;
  534.     }
  535.  
  536. /* Get lengths of months in year following jahrzeit */
  537.     len = DaysInHebYear(y+1);
  538.     monlen = DaysInHebMonths(len);
  539.  
  540.     if (d > monlen[m]) *ans = JAHR_FORWARD;
  541.     else               *ans = JAHR_BACKWARD;
  542.  
  543.     return OK;
  544. }
  545.