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