"Fossies" - the Fresh Open Source Software Archive

Member "remind-03.03.09/src/hbcal.c" (15 Oct 2021, 16051 Bytes) of package /linux/misc/remind-03.03.09.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "hbcal.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 03.03.06_vs_03.03.07.

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