1 /*
2    Hebcal - A Jewish Calendar Generator
3    Copyright (C) 1994-2004  Danny Sadinoff
4    Portions Copyright (c) 2002 Michael J. Radwin. All Rights Reserved.
5 
6    https://github.com/hebcal/hebcal
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License
10    as published by the Free Software Foundation; either version 2
11    of the License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22    Danny Sadinoff can be reached at
23 
24    danny@sadinoff.com
25  */
26 
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include "common.h"
30 #include "greg.h"
31 #include "hebcal.h"
32 
33 hmonths_t hMonths =
34 {
35     {
36         {"VOID"},
37         {"Nisan"},
38         {"Iyyar"},
39         {"Sivan"},
40         {"Tamuz"},
41         {"Av"},
42         {"Elul"},
43         {"Tishrei"},
44         {"Cheshvan"},
45         {"Kislev"},
46         {"Tevet"},
47         {"Sh'vat"},
48         {"Adar"},
49         {"Nisan"}
50     },
51     {
52         {"VOID"},
53         {"Nisan"},
54         {"Iyyar"},
55         {"Sivan"},
56         {"Tamuz"},
57         {"Av"},
58         {"Elul"},
59         {"Tishrei"},
60         {"Cheshvan"},
61         {"Kislev"},
62         {"Tevet"},
63         {"Sh'vat"},
64         {"Adar I"},
65         {"Adar II"},
66         {"Nisan"}
67     }
68 };
69 
max_days_in_heb_month(int month,int year)70 int max_days_in_heb_month (int month, int year)
71 {
72     if ( month == IYYAR ||
73          month == TAMUZ ||
74          month == ELUL ||
75          month == TEVET ||
76          month == ADAR_II ||
77          (month == ADAR_I && !LEAP_YR_HEB( year )) ||
78          (month == CHESHVAN && !long_cheshvan( year )) ||
79          (month == KISLEV && short_kislev( year )))
80         return 29;
81     else
82         return 30;
83 }
84 
lookup_hebrew_month(const char * s)85 int lookup_hebrew_month( const char *s )
86 {
87   /* the hebrew months are unique to their second letter
88      N         nisan  (november?)
89      I         iyyar
90      E        Elul
91      C        Cheshvan
92      K        Kislev
93      1        1Adar
94      2        2Adar
95      Si Sh     sivan, Shvat
96      Ta Ti Te Tamuz, Tishrei, Tevet
97      Av Ad    Av, Adar
98    */
99     switch ( tolower( *s++ ))
100     {
101     case 'n':
102         return (tolower (*s) == 'o') ?	/* this catches "november" */
103             0
104             : NISAN;
105     case 'i':
106         return IYYAR;
107     case 'e':
108         return ELUL;
109     case 'c':
110         return CHESHVAN;
111     case 'k':
112         return KISLEV;
113     case 's':
114         switch (tolower (*s))
115         {
116         case 'i':
117             return SIVAN;
118         case 'h':
119             return SHVAT;
120         default:
121             return 0;
122         }
123     case 't':
124         switch (tolower (*s))
125         {
126         case 'a':
127             return TAMUZ;
128         case 'i':
129             return TISHREI;
130         case 'e':
131             return TEVET;
132         default:
133             return 0;
134         }
135     case 'a':
136         switch (tolower (*s))
137         {
138         case 'v':
139             return AV;
140         case 'd':
141             for (; *s; s++)
142             {			/* scan for a 1. */
143                 if (*s == '1')
144                     return ADAR_I;
145             }
146             return ADAR_II;	/* else assume sheni */
147         default:
148             return 0;
149         }
150     default:
151         return 0;
152     }
153 }
154 
155 
156 
157 
158 /*
159    returns day of week, hours and chalakim of specified molad.
160  */
get_molad(int year,int month)161 molad_t get_molad( int year, int month)
162 {
163     molad_t retMolad;
164 
165     long yearl, m_elapsed, p_elapsed, h_elapsed, parts, m_adj;
166 
167     m_adj = (long) month;
168     m_adj -= 7;
169     if (m_adj < 0) m_adj += MONTHS_IN_HEB(year);
170 
171     yearl = (long) year;
172     m_elapsed = m_adj +
173         235L * ((yearl - 1L) / 19L) +
174     12L * ((yearl - 1L) % 19) +
175         ((((yearl - 1L) % 19L) * 7) + 1L) / 19L;
176 
177     p_elapsed = 204L + (793L * (m_elapsed % 1080));
178 
179     h_elapsed = 5L + (12L * m_elapsed) +
180         793L * (m_elapsed / 1080L) +
181         p_elapsed / 1080L -
182         6L;
183 
184     parts = (p_elapsed % 1080) + 1080 * (h_elapsed % 24);
185 
186     retMolad.day = 1L + 29L * m_elapsed + h_elapsed / 24L;
187     retMolad.hour = (int) (h_elapsed % 24L);
188     retMolad.chalakim = (int) (parts % 1080L);
189 
190     return retMolad;
191 
192 }
193 
194 
abs2hebrew(long d)195 date_t abs2hebrew( long d )
196 {
197     static int mmap[] =
198         {
199             KISLEV, TEVET, SHVAT, ADAR_I, NISAN,
200             IYYAR, SIVAN, TAMUZ,
201             TISHREI, TISHREI, TISHREI, CHESHVAN
202         };
203     date_t hebdate, gregdate;
204     int day, month, year;
205 
206     if( d >= 10555144L )
207     {
208         fprintf(stderr, "parameter to abs2hebrew  %ld out of range\n",
209                 d );
210         exit(1);
211     }
212 
213     gregdate = abs2greg (d);
214     hebdate.dd = 1;
215     hebdate.mm = 7;
216     year = 3760 + gregdate.yy;
217 
218     while (hebdate.yy = year + 1,
219            d >= hebrew2abs (hebdate))
220         year++;
221 
222     if( year >= 4635 && year < 10666  )
223     {
224         /* optimize search */
225         month = mmap[gregdate.mm - 1];
226     }
227     else
228     {
229         /* we're outside the usual range, so assume nothing about hebrew/gregorian calendar drift... */
230         month = TISHREI;
231     }
232 
233     while (hebdate.mm = month,
234            hebdate.dd = max_days_in_heb_month (month, year),
235            hebdate.yy = year,
236            d > hebrew2abs (hebdate))
237         month = (month % MONTHS_IN_HEB (year)) + 1;
238 
239     hebdate.dd = 1;
240 
241     day = (int) (d - hebrew2abs (hebdate) + 1L);
242     if( day < 0)
243     {
244         fprintf(stderr, "assertion failure d < hebrew2abs(m,d,y) => %ld < %ld!\n",
245                 d, hebrew2abs(hebdate));
246         exit(1);
247     }
248 
249     hebdate.dd = day;
250 
251     return hebdate;
252 }
253 
254 
255 /* Days from sunday prior to start of hebrew calendar to mean
256    conjunction of tishrei in hebrew YEAR
257  */
hebrew_elapsed_days(int year)258 static long int hebrew_elapsed_days (int year)
259 {
260     long int yearl, m_elapsed, p_elapsed, h_elapsed, parts, day, alt_day;
261 
262     yearl = (long) year;
263     m_elapsed = 235L * ((yearl - 1L) / 19L) +
264         12L * ((yearl - 1L) % 19L) +
265         ((((yearl - 1L) % 19L) * 7L) + 1L) / 19L;
266 
267     p_elapsed = 204L + (793L * (m_elapsed % 1080L));
268 
269     h_elapsed = 5L + (12L * m_elapsed) +
270         793L * (m_elapsed / 1080L) +
271         p_elapsed / 1080L;
272 
273     parts = (p_elapsed % 1080L) + 1080L * (h_elapsed % 24L);
274 
275     day = 1L + 29L * m_elapsed + h_elapsed / 24L;
276 
277     if ((parts >= 19440L) ||
278         ((2L == (day % 7L)) && (parts >= 9924L) && !(LEAP_YR_HEB (year))) ||
279         ((1L == (day % 7L)) && (parts >= 16789L) && LEAP_YR_HEB (year - 1)))
280         alt_day = day + 1L;
281     else
282         alt_day = day;
283 
284     if ((alt_day % 7L) == 0L ||
285         (alt_day % 7L) == 3L ||
286         (alt_day % 7L) == 5L)
287         return alt_day + 1L;
288     else
289         return alt_day;
290 }
291 
292 
293 
294 /* convert hebrew date to absolute date */
295 /*Absolute date of Hebrew DATE.
296    The absolute date is the number of days elapsed since the (imaginary)
297    Gregorian date Sunday, December 31, 1 BC. */
hebrew2abs(date_t d)298 long hebrew2abs (date_t d)
299 {
300     int m;
301     long tempabs = (long) d.dd;
302     long ret;
303 
304     if (d.mm < TISHREI)
305     {
306         for (m = TISHREI; m <= MONTHS_IN_HEB (d.yy); m++)
307             tempabs += (long) max_days_in_heb_month (m, d.yy);
308 
309         for (m = NISAN; m < d.mm; m++)
310             tempabs += (long) max_days_in_heb_month (m, d.yy);
311     }
312     else
313     {
314         for (m = TISHREI; m < d.mm; m++)
315             tempabs += (long) max_days_in_heb_month (m, d.yy);
316     }
317 
318 
319     ret = hebrew_elapsed_days (d.yy) - 1373429L + tempabs;
320     return ret;
321 }
322 
323 /* Number of days in the hebrew YEAR */
days_in_heb_year(int year)324 int days_in_heb_year( int year )
325 {
326     return (int) (hebrew_elapsed_days (year + 1) - hebrew_elapsed_days (year));
327 }
328 
329 /* true if Cheshvan is long in hebrew YEAR */
long_cheshvan(int year)330 int long_cheshvan( int year )
331 {
332     return ((days_in_heb_year (year) % 10) == 5);
333 }
334 
335 /* true if Cheshvan is long in hebrew YEAR */
short_kislev(int year)336 int short_kislev( int year )
337 {
338     return ((days_in_heb_year (year) % 10) == 3);
339 }
340