1 /*
2   This file is part of KOrganizer.
3 
4   SPDX-FileCopyrightText: 2003 Jonathan Singer <jsinger@leeta.net>
5   SPDX-FileCopyrightText: 2007 Loïc Corbasson <loic.corbasson@gmail.com>
6 
7   Calendar routines from Hebrew Calendar by Frank Yellin.
8   Based on some GNU Emacs code (lisp/calendar/cal-hebrew.el),
9   SPDX-FileCopyrightText: 1995, 1997 Free Software Foundation, Inc.
10   SPDX-FileContributor: Nachum Dershowitz <nachum@cs.uiuc.edu>
11   SPDX-FileContributor: Edward M. Reingold <reingold@cs.uiuc.edu>
12 
13   SPDX-License-Identifier: GPL-2.0-or-later
14 */
15 
16 #include "holiday.h"
17 #include "parsha.h"
18 
19 #include <KLocalizedString>
20 
findHoliday(const HebrewDate & hd,bool useIsraelSettings,bool showParsha,bool showChol,bool showOmer)21 QStringList Holiday::findHoliday(const HebrewDate &hd, bool useIsraelSettings, bool showParsha, bool showChol, bool showOmer)
22 {
23     return findHoliday(hd.month(),
24                        hd.day(),
25                        hd.dayOfWeek() + 1,
26                        hd.kvia(),
27                        hd.isOnHebrewLeapYear(),
28                        useIsraelSettings,
29                        hd.hebrewDayNumber(),
30                        hd.year(),
31                        showParsha,
32                        showChol,
33                        showOmer);
34 }
35 
findHoliday(int month,int day,int weekday,int kvia,bool isLeapYear,bool useIsraelSettings,int dayNumber,int year,bool showParsha,bool showChol,bool showOmer)36 QStringList Holiday::findHoliday(int month,
37                                  int day,
38                                  int weekday,
39                                  int kvia,
40                                  bool isLeapYear,
41                                  bool useIsraelSettings,
42                                  int dayNumber,
43                                  int year,
44                                  bool showParsha,
45                                  bool showChol,
46                                  bool showOmer)
47 {
48     enum {
49         Sunday = 1,
50         Monday,
51         Tuesday,
52         Wednesday,
53         Thursday,
54         Friday,
55         Saturday,
56     };
57 
58     QStringList holidays;
59     bool isAShabbat = (weekday == Saturday);
60 
61     // Treat Adar in a non-leap year as if it were Adar II.
62     if ((month == Adar) && !isLeapYear) {
63         month = AdarII;
64     }
65     switch (month) {
66     case Nissan:
67         switch (day) {
68         case 1:
69             if (isAShabbat) {
70                 holidays << i18nc(
71                     "These are Jewish holidays and mostly do not "
72                     "have translations. They may have different "
73                     "spellings in your language; otherwise, just "
74                     "translate the sound to your characters.",
75                     "Sh. HaHodesh");
76             }
77             break;
78         case 14:
79             if (!isAShabbat) {
80                 // If it's Shabbat, we have three pieces of info.
81                 // This is the least important, so we skip it on Shabbat as we only
82                 // really want the two most important ones.
83                 holidays << i18n("Erev Pesach");
84             }
85         /* fall through */
86         case 8:
87         case 9:
88         case 10:
89         case 11:
90         case 12:
91         case 13:
92             // The Saturday before Pesach (8th-14th)
93             if (isAShabbat) {
94                 holidays << i18n("Sh. HaGadol");
95             }
96             break;
97         case 15:
98         case 16:
99         case 21:
100         case 22:
101             if (!useIsraelSettings || (day == 15) || (day == 21)) {
102                 holidays << i18n("Pesach");
103                 break;
104             } else if (day == 22) {
105                 break;
106             }
107         /* else fall through */
108         case 17:
109         case 18:
110         case 19:
111         case 20:
112             if (showChol) {
113                 holidays << i18n("Chol Hamoed");
114             }
115             break;
116         case 26:
117         case 27:
118         case 28:
119             // Yom HaShoah only exists since Israel was established.
120             if (year > 1948 + 3760) {
121                 switch (weekday) {
122                 case Thursday:
123                     if (day == 26 || day == 27) {
124                         holidays << i18n("Yom HaShoah");
125                     }
126                     break;
127                 case Monday:
128                     if (day == 28 || day == 27) {
129                         holidays << i18n("Yom HaShoah");
130                     }
131                     break;
132                 case Sunday:
133                 case Friday:
134                     // These are never either of them.
135                     break;
136                 default:
137                     if (day == 27) {
138                         holidays << i18n("Yom HaShoah");
139                     }
140                     break;
141                 }
142             }
143             break;
144         }
145         if ((day > 15) && showOmer) {
146             // Count the Omer, starting after the first day of Pesach.
147             holidays << sfirah(day - 15);
148         }
149         break;
150 
151     case Iyar:
152         switch (day) {
153         case 2:
154         case 3:
155         case 4:
156         case 5:
157             // Yom HaAtzmaut is on the 5th, unless that's a Saturday, in which
158             // case it is moved back two days to Thursday. Yom HaZikaron is the
159             // day before Yom HaAtzmaut.
160             if (year >= 1948 + 3760) { // only after Israel was established
161                 switch (weekday) {
162                 case Wednesday:
163                     if (day == 5) {
164                         holidays << i18n("Yom HaAtzmaut");
165                     } else {
166                         holidays << i18n("Yom HaZikaron");
167                     }
168                     break;
169                 case Thursday:
170                     // This can't be 2 Iyar.
171                     holidays << i18n("Yom HaAtzmaut");
172                     break;
173                 case Friday:
174                 case Saturday:
175                     // These are never either of them.
176                     break;
177                 default:
178                     // All other days follow the normal rules.
179                     if (day == 4) {
180                         holidays << i18n("Yom HaZikaron");
181                     } else if (day == 5) {
182                         holidays << i18n("Yom HaAtzmaut");
183                     }
184                 }
185             }
186             break;
187         case 28:
188             if (year > 1967 + 3760) {
189                 // only since the 1967 war
190                 holidays << i18n("Yom Yerushalayim");
191             }
192             break;
193         case 18:
194             holidays << i18n("Lag BaOmer");
195             break;
196         }
197         if ((day != 18) && showOmer) {
198             // Sfirah the whole month, Lag BaOmer is already mentioned.
199             holidays << sfirah(day + 15);
200         }
201         break;
202 
203     case Sivan:
204         switch (day) {
205         case 1:
206         case 2:
207         case 3:
208         case 4:
209             // Sfirah until Shavuot
210             if (showOmer) {
211                 holidays << sfirah(day + 44);
212             }
213             break;
214         case 5:
215             // Don't need to mention Sfira(49) if there's already two other and
216             // more important pieces of information.
217             if (showOmer && !isAShabbat) {
218                 holidays << sfirah(49);
219             }
220             holidays << i18n("Erev Shavuot");
221             break;
222         case 6:;
223         case 7:
224             if (!useIsraelSettings || (day == 6)) {
225                 holidays << i18n("Shavuot");
226             }
227             break;
228         }
229         break;
230 
231     case Tamuz:
232         // 17th of Tamuz, except Shabbat pushes it to Sunday.
233         if ((!isAShabbat && (day == 17)) || ((weekday == Sunday) && (day == 18))) {
234             holidays << i18n("Tzom Tammuz");
235         }
236         break;
237 
238     case Ab:
239         if (isAShabbat && (3 <= day) && (day <= 16)) {
240             // The shabbat before and after Tisha B'Av are special
241             if (day <= 9) {
242                 holidays << i18n("Sh. Hazon");
243             } else {
244                 holidays << i18n("Sh. Nahamu");
245             }
246         } else if ((!isAShabbat && (day == 9)) || ((weekday == Sunday) && (day == 10))) {
247             // 9th of Av, except Shabbat pushes it to Sunday.
248             holidays << i18n("Tisha B'Av");
249         }
250         break;
251 
252     case Elul:
253         if ((day >= 20) && (day <= 26) && isAShabbat) {
254             holidays << i18n("S'lichot");
255         } else if (day == 29) {
256             holidays << i18n("Erev R.H.");
257         }
258         break;
259 
260     case Tishrei:
261         switch (day) {
262         case 1:;
263         case 2:
264             holidays << i18n("Rosh Hashana");
265             break;
266         case 3:
267             if (isAShabbat) {
268                 holidays << i18n("Sh. Shuvah");
269             } else {
270                 holidays << i18n("Tzom Gedalia");
271             }
272             break;
273         case 4:
274             if (weekday == Sunday) {
275                 holidays << i18n("Tzom Gedalia");
276             }
277         /* fall through */
278         case 5:
279         case 6:
280         case 7:
281         case 8:
282             if (isAShabbat) {
283                 holidays << i18n("Sh. Shuvah");
284             }
285             break;
286         case 9:
287             holidays << i18n("Erev Y.K.");
288             break;
289         case 10:
290             holidays << i18n("Yom Kippur");
291             break;
292         case 14:
293             holidays << i18n("Erev Sukkot");
294             break;
295         case 15:
296         case 16:
297             if (!useIsraelSettings || (day == 15)) {
298                 holidays << i18n("Sukkot");
299                 break;
300             }
301         /* else fall through */
302         case 17:
303         case 18:
304         case 19:
305         case 20:
306             if (showChol) {
307                 holidays << i18n("Chol Hamoed");
308             }
309             break;
310         case 21:
311             holidays << i18n("Hoshana Rabah");
312             break;
313         case 22:
314             holidays << i18n("Shmini Atzeret");
315             break;
316         case 23:
317             if (!useIsraelSettings) {
318                 holidays << i18n("Simchat Torah");
319             }
320             break;
321         }
322         break;
323 
324     case Cheshvan:
325         break;
326 
327     case Kislev:
328         if (day == 24) {
329             holidays << i18n("Erev Hanukah");
330         } else if (day >= 25) {
331             holidays << i18n("Hanukah");
332         }
333         break;
334 
335     case Tevet:
336         if (day <= (kvia == 0 ? 3 : 2)) {
337             // We need to know the length of Kislev to determine the last day of
338             // Chanukah.
339             holidays << i18n("Hanukah");
340         } else if (((day == 10) && !isAShabbat) || ((day == 11) && (weekday == Sunday))) {
341             // 10th of Tevet; Shabbat pushes it to Sunday.
342             holidays << i18n("Tzom Tevet");
343         }
344         break;
345 
346     case Shvat:
347         switch (day) {
348         // The info for figuring out Shabbat Shirah is from the Gnu code. I
349         // assume it's correct.
350         case 10:
351             if ((kvia != 0) && isAShabbat) {
352                 holidays << i18n("Sh. Shirah");
353             }
354             break;
355         case 11:
356         case 12:
357         case 13:
358         case 14:
359         case 16:
360             if (isAShabbat) {
361                 holidays << i18n("Sh. Shirah");
362             }
363             break;
364         case 15:
365             if (isAShabbat) {
366                 holidays << i18n("Sh. Shirah");
367             }
368             holidays << i18n("Tu B'Shvat");
369             break;
370         case 17:
371             if ((kvia == 0) && isAShabbat) {
372                 holidays << i18n("Sh. Shirah");
373             }
374             break;
375         case 25:
376         case 26:
377         case 27:
378         case 28:
379         case 29:
380         case 30:
381             // The last shabbat on or before 1 Adar or 1 AdarII
382             if (isAShabbat && !isLeapYear) {
383                 holidays << i18n("Sh. Shekalim");
384             }
385             break;
386         }
387         break;
388 
389     case AdarI:
390         if (day == 14) {
391             // Eat Purim Katan Candy
392             holidays << i18n("Purim Katan");
393         } else if ((day >= 25) && isAShabbat) {
394             // The last shabbat on or before 1 Adar II.
395             holidays << i18n("Sh. Shekalim");
396         }
397         break;
398 
399     case AdarII: /* Adar II or non-leap year Adar */
400         switch (day) {
401         case 1:
402             if (isAShabbat) {
403                 holidays << i18n("Sh. Shekalim");
404             }
405             break;
406         case 11:
407         case 12:
408             // Ta'anit ester is on the 13th.  But shabbat moves it back to
409             // Thursday.
410             if (weekday == Thursday) {
411                 holidays << i18n("Ta'anit Ester");
412             }
413         /* fall through */
414         case 7:
415         case 8:
416         case 9:
417         case 10:
418             // The Shabbat before purim is Shabbat Zachor
419             if (isAShabbat) {
420                 holidays << i18n("Sh. Zachor");
421             }
422             break;
423         case 13:
424             if (isAShabbat) {
425                 holidays << i18n("Sh. Zachor");
426             } else {
427                 holidays << i18n("Erev Purim");
428             }
429             // It's Ta'anit Esther, unless it's a Friday or Saturday
430             if (weekday < Friday) {
431                 holidays << i18n("Ta'anit Ester");
432             }
433             break;
434         case 14:
435             holidays << i18n("Purim");
436             break;
437         case 15:
438             if (!isAShabbat) {
439                 holidays << i18n("Shushan Purim");
440             }
441             break;
442         case 16:
443             if (weekday == Sunday) {
444                 holidays << i18n("Shushan Purim");
445             }
446             break;
447         case 17:
448         case 18:
449         case 19:
450         case 20:
451         case 21:
452         case 22:
453         case 23:
454             if (isAShabbat) {
455                 holidays << i18n("Sh. Parah");
456             }
457             break;
458         case 24:
459         case 25:
460         case 26:
461         case 27:
462         case 28:
463         case 29:
464             if (isAShabbat) {
465                 holidays << i18n("Sh. HaHodesh");
466             }
467             break;
468         }
469         break;
470     }
471     if (isAShabbat && showParsha) {
472         // Find the Parsha on Shabbat.
473         holidays << Parsha::findParshaName(dayNumber, kvia, isLeapYear, useIsraelSettings);
474     }
475     return holidays;
476 }
477 
sfirah(int day)478 QString Holiday::sfirah(int day)
479 {
480     QString buffer = QString::number(day);
481     buffer + i18n(" Omer"); // TODO: Find a way to write 1st instead of 1,
482     //                           2nd instead of 2, etc.
483     return buffer;
484 }
485