File indexing completed on 2025-01-19 04:46:46

0001 /*
0002   This file is part of KOrganizer.
0003 
0004   SPDX-FileCopyrightText: 2003 Jonathan Singer <jsinger@leeta.net>
0005   SPDX-FileCopyrightText: 2007 Loïc Corbasson <loic.corbasson@gmail.com>
0006 
0007   Calendar routines from Hebrew Calendar by Frank Yellin.
0008   Based on some GNU Emacs code (lisp/calendar/cal-hebrew.el),
0009   SPDX-FileCopyrightText: 1995, 1997 Free Software Foundation, Inc.
0010   SPDX-FileContributor: Nachum Dershowitz <nachum@cs.uiuc.edu>
0011   SPDX-FileContributor: Edward M. Reingold <reingold@cs.uiuc.edu>
0012 
0013   SPDX-License-Identifier: GPL-2.0-or-later
0014 */
0015 
0016 #include "holiday.h"
0017 #include "parsha.h"
0018 
0019 #include <KLocalizedString>
0020 
0021 QStringList Holiday::findHoliday(const HebrewDate &hd, bool useIsraelSettings, bool showParsha, bool showChol, bool showOmer)
0022 {
0023     return findHoliday(hd.month(),
0024                        hd.day(),
0025                        hd.dayOfWeek() + 1,
0026                        hd.kvia(),
0027                        hd.isOnHebrewLeapYear(),
0028                        useIsraelSettings,
0029                        hd.hebrewDayNumber(),
0030                        hd.year(),
0031                        showParsha,
0032                        showChol,
0033                        showOmer);
0034 }
0035 
0036 QStringList Holiday::findHoliday(int month,
0037                                  int day,
0038                                  int weekday,
0039                                  int kvia,
0040                                  bool isLeapYear,
0041                                  bool useIsraelSettings,
0042                                  int dayNumber,
0043                                  int year,
0044                                  bool showParsha,
0045                                  bool showChol,
0046                                  bool showOmer)
0047 {
0048     enum {
0049         Sunday = 1,
0050         Monday,
0051         Tuesday,
0052         Wednesday,
0053         Thursday,
0054         Friday,
0055         Saturday,
0056     };
0057 
0058     QStringList holidays;
0059     bool isAShabbat = (weekday == Saturday);
0060 
0061     // Treat Adar in a non-leap year as if it were Adar II.
0062     if ((month == Adar) && !isLeapYear) {
0063         month = AdarII;
0064     }
0065     switch (month) {
0066     case Nissan:
0067         switch (day) {
0068         case 1:
0069             if (isAShabbat) {
0070                 holidays << i18nc(
0071                     "These are Jewish holidays and mostly do not "
0072                     "have translations. They may have different "
0073                     "spellings in your language; otherwise, just "
0074                     "translate the sound to your characters.",
0075                     "Sh. HaHodesh");
0076             }
0077             break;
0078         case 14:
0079             if (!isAShabbat) {
0080                 // If it's Shabbat, we have three pieces of info.
0081                 // This is the least important, so we skip it on Shabbat as we only
0082                 // really want the two most important ones.
0083                 holidays << i18n("Erev Pesach");
0084             }
0085         /* fall through */
0086         case 8:
0087         case 9:
0088         case 10:
0089         case 11:
0090         case 12:
0091         case 13:
0092             // The Saturday before Pesach (8th-14th)
0093             if (isAShabbat) {
0094                 holidays << i18n("Sh. HaGadol");
0095             }
0096             break;
0097         case 15:
0098         case 16:
0099         case 21:
0100         case 22:
0101             if (!useIsraelSettings || (day == 15) || (day == 21)) {
0102                 holidays << i18n("Pesach");
0103                 break;
0104             } else if (day == 22) {
0105                 break;
0106             }
0107         /* else fall through */
0108         case 17:
0109         case 18:
0110         case 19:
0111         case 20:
0112             if (showChol) {
0113                 holidays << i18n("Chol Hamoed");
0114             }
0115             break;
0116         case 26:
0117         case 27:
0118         case 28:
0119             // Yom HaShoah only exists since Israel was established.
0120             if (year > 1948 + 3760) {
0121                 switch (weekday) {
0122                 case Thursday:
0123                     if (day == 26 || day == 27) {
0124                         holidays << i18n("Yom HaShoah");
0125                     }
0126                     break;
0127                 case Monday:
0128                     if (day == 28 || day == 27) {
0129                         holidays << i18n("Yom HaShoah");
0130                     }
0131                     break;
0132                 case Sunday:
0133                 case Friday:
0134                     // These are never either of them.
0135                     break;
0136                 default:
0137                     if (day == 27) {
0138                         holidays << i18n("Yom HaShoah");
0139                     }
0140                     break;
0141                 }
0142             }
0143             break;
0144         }
0145         if ((day > 15) && showOmer) {
0146             // Count the Omer, starting after the first day of Pesach.
0147             holidays << sfirah(day - 15);
0148         }
0149         break;
0150 
0151     case Iyar:
0152         switch (day) {
0153         case 2:
0154         case 3:
0155         case 4:
0156         case 5:
0157             // Yom HaAtzmaut is on the 5th, unless that's a Saturday, in which
0158             // case it is moved back two days to Thursday. Yom HaZikaron is the
0159             // day before Yom HaAtzmaut.
0160             if (year >= 1948 + 3760) { // only after Israel was established
0161                 switch (weekday) {
0162                 case Wednesday:
0163                     if (day == 5) {
0164                         holidays << i18n("Yom HaAtzmaut");
0165                     } else {
0166                         holidays << i18n("Yom HaZikaron");
0167                     }
0168                     break;
0169                 case Thursday:
0170                     // This can't be 2 Iyar.
0171                     holidays << i18n("Yom HaAtzmaut");
0172                     break;
0173                 case Friday:
0174                 case Saturday:
0175                     // These are never either of them.
0176                     break;
0177                 default:
0178                     // All other days follow the normal rules.
0179                     if (day == 4) {
0180                         holidays << i18n("Yom HaZikaron");
0181                     } else if (day == 5) {
0182                         holidays << i18n("Yom HaAtzmaut");
0183                     }
0184                 }
0185             }
0186             break;
0187         case 28:
0188             if (year > 1967 + 3760) {
0189                 // only since the 1967 war
0190                 holidays << i18n("Yom Yerushalayim");
0191             }
0192             break;
0193         case 18:
0194             holidays << i18n("Lag BaOmer");
0195             break;
0196         }
0197         if ((day != 18) && showOmer) {
0198             // Sfirah the whole month, Lag BaOmer is already mentioned.
0199             holidays << sfirah(day + 15);
0200         }
0201         break;
0202 
0203     case Sivan:
0204         switch (day) {
0205         case 1:
0206         case 2:
0207         case 3:
0208         case 4:
0209             // Sfirah until Shavuot
0210             if (showOmer) {
0211                 holidays << sfirah(day + 44);
0212             }
0213             break;
0214         case 5:
0215             // Don't need to mention Sfira(49) if there's already two other and
0216             // more important pieces of information.
0217             if (showOmer && !isAShabbat) {
0218                 holidays << sfirah(49);
0219             }
0220             holidays << i18n("Erev Shavuot");
0221             break;
0222         case 6:;
0223         case 7:
0224             if (!useIsraelSettings || (day == 6)) {
0225                 holidays << i18n("Shavuot");
0226             }
0227             break;
0228         }
0229         break;
0230 
0231     case Tamuz:
0232         // 17th of Tamuz, except Shabbat pushes it to Sunday.
0233         if ((!isAShabbat && (day == 17)) || ((weekday == Sunday) && (day == 18))) {
0234             holidays << i18n("Tzom Tammuz");
0235         }
0236         break;
0237 
0238     case Ab:
0239         if (isAShabbat && (3 <= day) && (day <= 16)) {
0240             // The shabbat before and after Tisha B'Av are special
0241             if (day <= 9) {
0242                 holidays << i18n("Sh. Hazon");
0243             } else {
0244                 holidays << i18n("Sh. Nahamu");
0245             }
0246         } else if ((!isAShabbat && (day == 9)) || ((weekday == Sunday) && (day == 10))) {
0247             // 9th of Av, except Shabbat pushes it to Sunday.
0248             holidays << i18n("Tisha B'Av");
0249         }
0250         break;
0251 
0252     case Elul:
0253         if ((day >= 20) && (day <= 26) && isAShabbat) {
0254             holidays << i18n("S'lichot");
0255         } else if (day == 29) {
0256             holidays << i18n("Erev R.H.");
0257         }
0258         break;
0259 
0260     case Tishrei:
0261         switch (day) {
0262         case 1:;
0263         case 2:
0264             holidays << i18n("Rosh Hashana");
0265             break;
0266         case 3:
0267             if (isAShabbat) {
0268                 holidays << i18n("Sh. Shuvah");
0269             } else {
0270                 holidays << i18n("Tzom Gedalia");
0271             }
0272             break;
0273         case 4:
0274             if (weekday == Sunday) {
0275                 holidays << i18n("Tzom Gedalia");
0276             }
0277         /* fall through */
0278         case 5:
0279         case 6:
0280         case 7:
0281         case 8:
0282             if (isAShabbat) {
0283                 holidays << i18n("Sh. Shuvah");
0284             }
0285             break;
0286         case 9:
0287             holidays << i18n("Erev Y.K.");
0288             break;
0289         case 10:
0290             holidays << i18n("Yom Kippur");
0291             break;
0292         case 14:
0293             holidays << i18n("Erev Sukkot");
0294             break;
0295         case 15:
0296         case 16:
0297             if (!useIsraelSettings || (day == 15)) {
0298                 holidays << i18n("Sukkot");
0299                 break;
0300             }
0301         /* else fall through */
0302         case 17:
0303         case 18:
0304         case 19:
0305         case 20:
0306             if (showChol) {
0307                 holidays << i18n("Chol Hamoed");
0308             }
0309             break;
0310         case 21:
0311             holidays << i18n("Hoshana Rabah");
0312             break;
0313         case 22:
0314             holidays << i18n("Shmini Atzeret");
0315             break;
0316         case 23:
0317             if (!useIsraelSettings) {
0318                 holidays << i18n("Simchat Torah");
0319             }
0320             break;
0321         }
0322         break;
0323 
0324     case Cheshvan:
0325         break;
0326 
0327     case Kislev:
0328         if (day == 24) {
0329             holidays << i18n("Erev Hanukah");
0330         } else if (day >= 25) {
0331             holidays << i18n("Hanukah");
0332         }
0333         break;
0334 
0335     case Tevet:
0336         if (day <= (kvia == 0 ? 3 : 2)) {
0337             // We need to know the length of Kislev to determine the last day of
0338             // Chanukah.
0339             holidays << i18n("Hanukah");
0340         } else if (((day == 10) && !isAShabbat) || ((day == 11) && (weekday == Sunday))) {
0341             // 10th of Tevet; Shabbat pushes it to Sunday.
0342             holidays << i18n("Tzom Tevet");
0343         }
0344         break;
0345 
0346     case Shvat:
0347         switch (day) {
0348         // The info for figuring out Shabbat Shirah is from the Gnu code. I
0349         // assume it's correct.
0350         case 10:
0351             if ((kvia != 0) && isAShabbat) {
0352                 holidays << i18n("Sh. Shirah");
0353             }
0354             break;
0355         case 11:
0356         case 12:
0357         case 13:
0358         case 14:
0359         case 16:
0360             if (isAShabbat) {
0361                 holidays << i18n("Sh. Shirah");
0362             }
0363             break;
0364         case 15:
0365             if (isAShabbat) {
0366                 holidays << i18n("Sh. Shirah");
0367             }
0368             holidays << i18n("Tu B'Shvat");
0369             break;
0370         case 17:
0371             if ((kvia == 0) && isAShabbat) {
0372                 holidays << i18n("Sh. Shirah");
0373             }
0374             break;
0375         case 25:
0376         case 26:
0377         case 27:
0378         case 28:
0379         case 29:
0380         case 30:
0381             // The last shabbat on or before 1 Adar or 1 AdarII
0382             if (isAShabbat && !isLeapYear) {
0383                 holidays << i18n("Sh. Shekalim");
0384             }
0385             break;
0386         }
0387         break;
0388 
0389     case AdarI:
0390         if (day == 14) {
0391             // Eat Purim Katan Candy
0392             holidays << i18n("Purim Katan");
0393         } else if ((day >= 25) && isAShabbat) {
0394             // The last shabbat on or before 1 Adar II.
0395             holidays << i18n("Sh. Shekalim");
0396         }
0397         break;
0398 
0399     case AdarII: /* Adar II or non-leap year Adar */
0400         switch (day) {
0401         case 1:
0402             if (isAShabbat) {
0403                 holidays << i18n("Sh. Shekalim");
0404             }
0405             break;
0406         case 11:
0407         case 12:
0408             // Ta'anit ester is on the 13th.  But shabbat moves it back to
0409             // Thursday.
0410             if (weekday == Thursday) {
0411                 holidays << i18n("Ta'anit Ester");
0412             }
0413         /* fall through */
0414         case 7:
0415         case 8:
0416         case 9:
0417         case 10:
0418             // The Shabbat before purim is Shabbat Zachor
0419             if (isAShabbat) {
0420                 holidays << i18n("Sh. Zachor");
0421             }
0422             break;
0423         case 13:
0424             if (isAShabbat) {
0425                 holidays << i18n("Sh. Zachor");
0426             } else {
0427                 holidays << i18n("Erev Purim");
0428             }
0429             // It's Ta'anit Esther, unless it's a Friday or Saturday
0430             if (weekday < Friday) {
0431                 holidays << i18n("Ta'anit Ester");
0432             }
0433             break;
0434         case 14:
0435             holidays << i18n("Purim");
0436             break;
0437         case 15:
0438             if (!isAShabbat) {
0439                 holidays << i18n("Shushan Purim");
0440             }
0441             break;
0442         case 16:
0443             if (weekday == Sunday) {
0444                 holidays << i18n("Shushan Purim");
0445             }
0446             break;
0447         case 17:
0448         case 18:
0449         case 19:
0450         case 20:
0451         case 21:
0452         case 22:
0453         case 23:
0454             if (isAShabbat) {
0455                 holidays << i18n("Sh. Parah");
0456             }
0457             break;
0458         case 24:
0459         case 25:
0460         case 26:
0461         case 27:
0462         case 28:
0463         case 29:
0464             if (isAShabbat) {
0465                 holidays << i18n("Sh. HaHodesh");
0466             }
0467             break;
0468         }
0469         break;
0470     }
0471     if (isAShabbat && showParsha) {
0472         // Find the Parsha on Shabbat.
0473         holidays << Parsha::findParshaName(dayNumber, kvia, isLeapYear, useIsraelSettings);
0474     }
0475     return holidays;
0476 }
0477 
0478 QString Holiday::sfirah(int day)
0479 {
0480     QString buffer = QString::number(day);
0481     buffer + i18n(" Omer"); // TODO: Find a way to write 1st instead of 1,
0482     //                           2nd instead of 2, etc.
0483     return buffer;
0484 }