python-hebrewdate 0.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hebrewdate/__init__.py ADDED
@@ -0,0 +1,29 @@
1
+ from .hebrewdate import (
2
+ HebrewMonth,
3
+ ShabbatType,
4
+ ShabbatChodeshType,
5
+ YearLength,
6
+ YearType,
7
+ HebrewDate,
8
+ HebrewMonthCalendar,
9
+ HebrewYearCalendar,
10
+ HebrewWeekdayDayNames,
11
+ HebrewWeekdayNightNames,
12
+ HebrewMonthNames,
13
+ ShabbatTypeNames,
14
+ ShabbatChodeshTypeNames,
15
+ )
16
+ from .hebrewholiday import (
17
+ HebrewHolidayId,
18
+ DiasporaHolidayId,
19
+ HebrewSecondYomTovId,
20
+ HebrewHoliday,
21
+ HolidayNames,
22
+ )
23
+ from .torahschedule import (
24
+ Parashah,
25
+ HolidayReading,
26
+ ParashahNames,
27
+ HolidayReadingNames,
28
+ TorahSchedule,
29
+ )
@@ -0,0 +1,542 @@
1
+ from enum import IntEnum
2
+ from date import Date, Weekday, WeekdayNames
3
+
4
+
5
+ class HebrewMonth(IntEnum):
6
+ NISAN = 1
7
+ IYAR = 2
8
+ SIVAN = 3
9
+ TAMMUZ = 4
10
+ AV = 5
11
+ ELUL = 6
12
+ TISHREI = 7
13
+ CHESHVAN = 8
14
+ KISLEV = 9
15
+ TEVET = 10
16
+ SHEVAT = 11
17
+ ADAR = 12
18
+ ADAR_II = 13
19
+
20
+ class ShabbatType(IntEnum):
21
+ NONE = 0
22
+ SHEKALIM = 1
23
+ ZAHOR = 2
24
+ PARAH = 3
25
+ HAHODESH = 4
26
+ HAGGADOL = 5
27
+ SHUVAH = 6
28
+ CHAZON = 7
29
+ NACHAMU = 8
30
+
31
+ class ShabbatChodeshType(IntEnum):
32
+ NONE = 0
33
+ MACHAR_CHODESH = 1
34
+ ROSH_CHODESH = 2
35
+
36
+ class YearLength(IntEnum):
37
+ DEFICIENT = 1
38
+ REGULAR = 2
39
+ COMPLETE = 3
40
+
41
+ class YearType(IntEnum):
42
+ B_CH_G = 1
43
+ B_SH_H = 2
44
+ G_K_H = 3
45
+ H_K_Z = 4
46
+ H_SH_A = 5
47
+ Z_CH_A = 6
48
+ Z_SH_G = 7
49
+ B_CH_H = 8
50
+ B_SH_Z = 9
51
+ G_K_Z = 10
52
+ H_CH_A = 11
53
+ H_SH_G = 12
54
+ Z_CH_G = 13
55
+ Z_SH_H = 14
56
+
57
+
58
+ class HebrewDate:
59
+ EPOCH = 347996
60
+
61
+ def __init__(self, year=1, month=HebrewMonth.TISHREI, day=1):
62
+ self.year = year
63
+ self.month = month
64
+ self.day = day
65
+
66
+ raw = day
67
+ if month < HebrewMonth.TISHREI:
68
+ for m in range(HebrewMonth.TISHREI, HebrewDate.numMonthInYear(year) + 1):
69
+ raw += HebrewDate.numdaysinmonth(year, m)
70
+ for m in range(HebrewMonth.NISAN, month):
71
+ raw += HebrewDate.numdaysinmonth(year, m)
72
+ else:
73
+ for m in range(HebrewMonth.TISHREI, month):
74
+ raw += HebrewDate.numdaysinmonth(year, m)
75
+ raw += HebrewDate.elapsedDays(year)
76
+ self.ordinal = raw + HebrewDate.EPOCH
77
+
78
+ @classmethod
79
+ def fromordinal(cls, ordinal):
80
+ raw = ordinal - HebrewDate.EPOCH
81
+
82
+ y = raw // 366
83
+ while True:
84
+ tempRaw = cls(y + 1, HebrewMonth.TISHREI, 1).ordinal - HebrewDate.EPOCH
85
+ if raw < tempRaw:
86
+ break
87
+ y += 1
88
+
89
+ raw1Nisan = cls(y, HebrewMonth.NISAN, 1).ordinal - HebrewDate.EPOCH
90
+ start = HebrewMonth.TISHREI if raw < raw1Nisan else HebrewMonth.NISAN
91
+
92
+ m = start
93
+ while True:
94
+ monthEnd = cls(y, m, HebrewDate.numdaysinmonth(y, m)).ordinal - HebrewDate.EPOCH
95
+ if raw <= monthEnd:
96
+ break
97
+ m += 1
98
+
99
+ day = raw - (cls(y, m, 1).ordinal - HebrewDate.EPOCH) + 1
100
+
101
+ return cls(y, m, day)
102
+
103
+ @classmethod
104
+ def fromdate(cls, date):
105
+ return cls.fromordinal(date.ordinal)
106
+
107
+ @property
108
+ def next(self):
109
+ return HebrewDate.fromordinal(self.ordinal + 1)
110
+
111
+ @property
112
+ def prev(self):
113
+ return HebrewDate.fromordinal(self.ordinal - 1)
114
+
115
+ @staticmethod
116
+ def isleapyear(year):
117
+ return ((year * 7) + 1) % 19 < 7
118
+
119
+ @staticmethod
120
+ def numMonthInYear(year):
121
+ return HebrewMonth.ADAR_II if HebrewDate.isleapyear(year) else HebrewMonth.ADAR
122
+
123
+ @staticmethod
124
+ def elapsedDays(year):
125
+ monthsElapsed = 235 * ((year - 1) // 19)
126
+ monthsElapsed += 12 * ((year - 1) % 19)
127
+ monthsElapsed += (((year - 1) % 19 * 7 + 1) // 19)
128
+
129
+ partsElapsed = ((monthsElapsed % 1080) * 793) + 204
130
+ hoursElapsed = 5 + (monthsElapsed * 12) + \
131
+ ((monthsElapsed // 1080) * 793) + (partsElapsed // 1080)
132
+
133
+ day = 1 + (29 * monthsElapsed) + (hoursElapsed // 24)
134
+ parts = ((hoursElapsed % 24) * 1080) + (partsElapsed % 1080)
135
+
136
+ addDay = (parts >= 19440) or \
137
+ (day % 7 == 2 and parts >= 9924 and not HebrewDate.isleapyear(year)) or \
138
+ (day % 7 == 1 and parts >= 16789 and HebrewDate.isleapyear(year - 1))
139
+
140
+ altDay = day + 1 if addDay else day
141
+ if altDay % 7 == 0 or altDay % 7 == 3 or altDay % 7 == 5:
142
+ altDay += 1
143
+ return altDay
144
+
145
+ @staticmethod
146
+ def numDaysInYear(year):
147
+ return HebrewDate.elapsedDays(year + 1) - HebrewDate.elapsedDays(year)
148
+
149
+ @staticmethod
150
+ def hasLongHeshvan(year):
151
+ return HebrewDate.numDaysInYear(year) % 10 == 5
152
+
153
+ @staticmethod
154
+ def hasShortKislev(year):
155
+ return HebrewDate.numDaysInYear(year) % 10 == 3
156
+
157
+ @staticmethod
158
+ def numdaysinmonth(year, month):
159
+ if month in (HebrewMonth.IYAR, HebrewMonth.TAMMUZ, HebrewMonth.ELUL, HebrewMonth.TEVET, HebrewMonth.ADAR_II):
160
+ return 29
161
+ if month == HebrewMonth.ADAR and not HebrewDate.isleapyear(year):
162
+ return 29
163
+ if month == HebrewMonth.CHESHVAN and not HebrewDate.hasLongHeshvan(year):
164
+ return 29
165
+ if month == HebrewMonth.KISLEV and HebrewDate.hasShortKislev(year):
166
+ return 29
167
+ return 30
168
+
169
+ @staticmethod
170
+ def yearLengthType(year):
171
+ if HebrewDate.hasLongHeshvan(year) and not HebrewDate.hasShortKislev(year):
172
+ return YearLength.COMPLETE
173
+ if not HebrewDate.hasLongHeshvan(year) and HebrewDate.hasShortKislev(year):
174
+ return YearLength.DEFICIENT
175
+ return YearLength.REGULAR
176
+
177
+ @staticmethod
178
+ def yeartype(year):
179
+ rh = HebrewDate(year, HebrewMonth.TISHREI, 1).dayofweek
180
+ pesach = HebrewDate(year, HebrewMonth.NISAN, 15).dayofweek
181
+ length = HebrewDate.yearLengthType(year)
182
+ if not HebrewDate.isleapyear(year):
183
+ if rh == Weekday.MONDAY and length == YearLength.DEFICIENT and pesach == Weekday.TUESDAY:
184
+ return YearType.B_CH_G
185
+ if rh == Weekday.MONDAY and length == YearLength.COMPLETE and pesach == Weekday.THURSDAY:
186
+ return YearType.B_SH_H
187
+ if rh == Weekday.TUESDAY and length == YearLength.REGULAR and pesach == Weekday.THURSDAY:
188
+ return YearType.G_K_H
189
+ if rh == Weekday.THURSDAY and length == YearLength.REGULAR and pesach == Weekday.SATURDAY:
190
+ return YearType.H_K_Z
191
+ if rh == Weekday.THURSDAY and length == YearLength.COMPLETE and pesach == Weekday.SUNDAY:
192
+ return YearType.H_SH_A
193
+ if rh == Weekday.SATURDAY and length == YearLength.DEFICIENT and pesach == Weekday.SUNDAY:
194
+ return YearType.Z_CH_A
195
+ if rh == Weekday.SATURDAY and length == YearLength.COMPLETE and pesach == Weekday.TUESDAY:
196
+ return YearType.Z_SH_G
197
+ else:
198
+ if rh == Weekday.MONDAY and length == YearLength.DEFICIENT and pesach == Weekday.THURSDAY:
199
+ return YearType.B_CH_H
200
+ if rh == Weekday.MONDAY and length == YearLength.COMPLETE and pesach == Weekday.SATURDAY:
201
+ return YearType.B_SH_Z
202
+ if rh == Weekday.TUESDAY and length == YearLength.REGULAR and pesach == Weekday.SATURDAY:
203
+ return YearType.G_K_Z
204
+ if rh == Weekday.THURSDAY and length == YearLength.DEFICIENT and pesach == Weekday.SUNDAY:
205
+ return YearType.H_CH_A
206
+ if rh == Weekday.THURSDAY and length == YearLength.COMPLETE and pesach == Weekday.TUESDAY:
207
+ return YearType.H_SH_G
208
+ if rh == Weekday.SATURDAY and length == YearLength.DEFICIENT and pesach == Weekday.TUESDAY:
209
+ return YearType.Z_CH_G
210
+ if rh == Weekday.SATURDAY and length == YearLength.COMPLETE and pesach == Weekday.THURSDAY:
211
+ return YearType.Z_SH_H
212
+ return 0
213
+
214
+
215
+ @staticmethod
216
+ def biblical(year, civil_month):
217
+ is_leap = HebrewDate.isleapyear(year)
218
+ if civil_month <= 6:
219
+ return civil_month + 6
220
+ elif civil_month == 7:
221
+ return 13 if is_leap else 1
222
+ else:
223
+ return civil_month - 7 if is_leap else civil_month - 6
224
+
225
+
226
+ @property
227
+ def dayofweek(self):
228
+ return (self.ordinal % 7 + 1) % 7 + 1
229
+
230
+ @property
231
+ def shabbat(self):
232
+ return HebrewDate.fromordinal(self.ordinal + (7 - self.dayofweek))
233
+
234
+ @property
235
+ def shabbatType(self):
236
+ sh = self.shabbat
237
+ year = sh.year
238
+
239
+ anchor = HebrewDate(year, HebrewMonth.NISAN, 1)
240
+ hahodeshShabbat = HebrewDate.fromordinal(anchor.ordinal - (anchor.dayofweek % 7))
241
+ if sh.ordinal == hahodeshShabbat.ordinal:
242
+ return ShabbatType.HAHODESH
243
+
244
+ if sh.ordinal == hahodeshShabbat.ordinal - 7:
245
+ return ShabbatType.PARAH
246
+
247
+ adarMonth = HebrewDate.numMonthInYear(year)
248
+ anchor = HebrewDate(year, adarMonth, 13)
249
+ zahorShabbat = HebrewDate.fromordinal(anchor.ordinal - (anchor.dayofweek % 7))
250
+ if sh.ordinal == zahorShabbat.ordinal:
251
+ return ShabbatType.ZAHOR
252
+
253
+ anchor = HebrewDate(year, adarMonth, 1)
254
+ shekalimShabbat = HebrewDate.fromordinal(anchor.ordinal - (anchor.dayofweek % 7))
255
+ if sh.ordinal == shekalimShabbat.ordinal:
256
+ return ShabbatType.SHEKALIM
257
+
258
+ anchor = HebrewDate(year, HebrewMonth.NISAN, 14)
259
+ haggadolShabbat = HebrewDate.fromordinal(anchor.ordinal - (anchor.dayofweek % 7))
260
+ if sh.ordinal == haggadolShabbat.ordinal:
261
+ return ShabbatType.HAGGADOL
262
+
263
+ anchor = HebrewDate(year, HebrewMonth.TISHREI, 9)
264
+ shuvahShabbat = HebrewDate.fromordinal(anchor.ordinal - (anchor.dayofweek % 7))
265
+ if sh.ordinal == shuvahShabbat.ordinal:
266
+ return ShabbatType.SHUVAH
267
+
268
+ anchor = HebrewDate(year, HebrewMonth.AV, 9)
269
+ chazonShabbat = HebrewDate.fromordinal(anchor.ordinal - (anchor.dayofweek % 7))
270
+ if sh.ordinal == chazonShabbat.ordinal:
271
+ return ShabbatType.CHAZON
272
+
273
+ dayAfter = HebrewDate.fromordinal(anchor.ordinal + 1)
274
+ nachamuShabbat = HebrewDate.fromordinal(dayAfter.ordinal + (7 - dayAfter.dayofweek))
275
+ if sh.ordinal == nachamuShabbat.ordinal:
276
+ return ShabbatType.NACHAMU
277
+
278
+ return None
279
+
280
+ @property
281
+ def shabbatChodeshType(self):
282
+ sh = self.shabbat
283
+
284
+ if sh.day == 1 and sh.month != HebrewMonth.TISHREI:
285
+ return ShabbatChodeshType.ROSH_CHODESH
286
+
287
+ nextDay = HebrewDate.fromordinal(sh.ordinal + 1)
288
+ if nextDay.day == 1 and nextDay.month != HebrewMonth.TISHREI:
289
+ return ShabbatChodeshType.MACHAR_CHODESH
290
+
291
+ return None
292
+
293
+ def __repr__(self):
294
+ return f"HebrewDate({self.year}, {self.month}, {self.day})"
295
+
296
+ def __eq__(self, other):
297
+ return isinstance(other, HebrewDate) and self.ordinal == other.ordinal
298
+
299
+ def __lt__(self, other):
300
+ return isinstance(other, HebrewDate) and self.ordinal < other.ordinal
301
+
302
+ def __le__(self, other):
303
+ return isinstance(other, HebrewDate) and self.ordinal <= other.ordinal
304
+
305
+ def __gt__(self, other):
306
+ return isinstance(other, HebrewDate) and self.ordinal > other.ordinal
307
+
308
+ def __ge__(self, other):
309
+ return isinstance(other, HebrewDate) and self.ordinal >= other.ordinal
310
+
311
+ def __hash__(self):
312
+ return hash(self.ordinal)
313
+
314
+
315
+ class HebrewMonthCalendar:
316
+ def __init__(self, year, month):
317
+ daysInMonth = HebrewDate.numdaysinmonth(year, month)
318
+ firstDate = HebrewDate(year, month, 1)
319
+ startCol = firstDate.dayofweek - 1
320
+
321
+ totalCells = startCol + daysInMonth
322
+ rowCount = (totalCells + 6) // 7
323
+
324
+ self.dates = [[None] * 7 for _ in range(6)]
325
+
326
+ dayCounter = 1
327
+ for r in range(rowCount):
328
+ for c in range(7):
329
+ if (r == 0 and c < startCol) or dayCounter > daysInMonth:
330
+ self.dates[r][c] = None
331
+ else:
332
+ self.dates[r][c] = HebrewDate(year, month, dayCounter)
333
+ dayCounter += 1
334
+
335
+
336
+ class HebrewYearCalendar:
337
+ def __init__(self, year):
338
+ self.year = year
339
+ self.monthCalendars = []
340
+ for month in range(HebrewMonth.TISHREI, HebrewDate.numMonthInYear(year) + 1):
341
+ self.monthCalendars.append(HebrewMonthCalendar(year, month))
342
+ for month in range(HebrewMonth.NISAN, HebrewMonth.TISHREI):
343
+ self.monthCalendars.append(HebrewMonthCalendar(year, month))
344
+
345
+ @property
346
+ def weeks(self):
347
+ start = HebrewDate(self.year, HebrewMonth.TISHREI, 1)
348
+ end = HebrewDate.fromordinal(start.ordinal + HebrewDate.numDaysInYear(self.year) - 1)
349
+ cur = start
350
+ while cur.dayofweek != 1:
351
+ cur = cur.prev
352
+ first_sunday = cur
353
+ cur = end
354
+ while cur.dayofweek != 7:
355
+ cur = cur.next
356
+ last_saturday = cur
357
+ weeks = []
358
+ d = first_sunday
359
+ while d.ordinal <= last_saturday.ordinal:
360
+ week = []
361
+ for _ in range(7):
362
+ if d.ordinal < start.ordinal or d.ordinal > end.ordinal:
363
+ week.append(None)
364
+ else:
365
+ week.append(d)
366
+ d = d.next
367
+ weeks.append(week)
368
+ return weeks
369
+
370
+
371
+ @property
372
+ def saturdays(self):
373
+ return [week[6] for week in self.weeks if week[6]]
374
+
375
+
376
+
377
+
378
+
379
+
380
+
381
+ class HebrewWeekdayDayNames:
382
+ NAMES_EN = [
383
+ "",
384
+ "First day",
385
+ "Second day",
386
+ "Third day",
387
+ "Fourth day",
388
+ "Fifth day",
389
+ "Sixth day",
390
+ "Shabbat",
391
+ ]
392
+ NAMES_HE = [
393
+ "",
394
+ "יום ראשון",
395
+ "יום שני",
396
+ "יום שלישי",
397
+ "יום רביעי",
398
+ "יום חמישי",
399
+ "יום שישי",
400
+ "יום שבת",
401
+ ]
402
+
403
+ def __init__(self, lang, dayofweek):
404
+ self.lang = lang
405
+ self.dayofweek = dayofweek
406
+
407
+ def name(self):
408
+ if self.lang == 'en':
409
+ return self.NAMES_EN[self.dayofweek]
410
+ return self.NAMES_HE[self.dayofweek]
411
+
412
+ class HebrewWeekdayNightNames:
413
+ NAMES_EN = [
414
+ "",
415
+ "Eve of first day",
416
+ "Eve of second day",
417
+ "Eve of third day",
418
+ "Eve of fourth day",
419
+ "Eve of fifth day",
420
+ "Eve of sixth day",
421
+ "Eve of Shabbat",
422
+ ]
423
+ NAMES_HE = [
424
+ "",
425
+ "ליל ראשון",
426
+ "ליל שני",
427
+ "ליל שלישי",
428
+ "ליל רביעי",
429
+ "ליל חמישי",
430
+ "ליל שישי",
431
+ "ליל שבת",
432
+ ]
433
+
434
+ def __init__(self, lang, dayofweek):
435
+ self.lang = lang
436
+ self.dayofweek = dayofweek
437
+
438
+ def name(self):
439
+ if self.lang == 'en':
440
+ return self.NAMES_EN[self.dayofweek]
441
+ return self.NAMES_HE[self.dayofweek]
442
+
443
+
444
+
445
+
446
+
447
+
448
+
449
+ class HebrewMonthNames:
450
+ NAMES_EN = [
451
+ "", "Nisan", "Iyar", "Sivan", "Tammuz", "Av", "Elul",
452
+ "Tishrei", "Cheshvan", "Kislev", "Tevet", "Shevat", "Adar", "Adar II",
453
+ ]
454
+ NAMES_HE = [
455
+ "", "ניסן", "אייר", "סיוון", "תמוז", "אב", "אלול",
456
+ "תשרי", "חשון", "כסלו", "טבת", "שבט", "אדר", "אדר ב׳",
457
+ ]
458
+
459
+ def __init__(self, lang, year, month):
460
+ self.lang = lang
461
+ self.year = year
462
+ self.month = month
463
+
464
+ def name(self):
465
+ if self.lang == 'en':
466
+ if self.month == HebrewMonth.ADAR and HebrewDate.isleapyear(self.year):
467
+ return "Adar I"
468
+ return self.NAMES_EN[self.month]
469
+ elif self.lang == 'he':
470
+ if self.month == HebrewMonth.ADAR and HebrewDate.isleapyear(self.year):
471
+ return "אדר א׳"
472
+ return self.NAMES_HE[self.month]
473
+ return ""
474
+
475
+
476
+ class ShabbatTypeNames:
477
+ NAMES_EN = [
478
+ "", "Shekalim", "Zachor", "Parah", "HaChodesh", "HaGadol",
479
+ "Shuvah", "Chazon", "Nachamu",
480
+ ]
481
+ NAMES_HE = [
482
+ "", "שקלים", "זכור", "פרה", "החודש", "הגדול",
483
+ "שובה", "חזון", "נחמו",
484
+ ]
485
+
486
+ def __init__(self, lang, shabbatType):
487
+ self.lang = lang
488
+ self.shabbatType = shabbatType
489
+
490
+ def name(self):
491
+ if self.lang == 'en':
492
+ return self.NAMES_EN[self.shabbatType]
493
+ return self.NAMES_HE[self.shabbatType]
494
+
495
+
496
+ class ShabbatChodeshTypeNames:
497
+ NAMES_EN = ["", "Machar Chodesh", "Rosh Chodesh"]
498
+ NAMES_HE = ["", "מחר חודש", "ראש חודש"]
499
+
500
+ def __init__(self, lang, shabbatChodeshType):
501
+ self.lang = lang
502
+ self.shabbatChodeshType = shabbatChodeshType
503
+
504
+ def name(self):
505
+ if self.lang == 'en':
506
+ return self.NAMES_EN[self.shabbatChodeshType]
507
+ return self.NAMES_HE[self.shabbatChodeshType]
508
+
509
+
510
+ if __name__ == "__main__":
511
+ import time as _systime
512
+ from date import Date
513
+
514
+ now = _systime.localtime()
515
+ today = Date(now.tm_year, now.tm_mon, now.tm_mday)
516
+ hToday = HebrewDate.fromdate(today)
517
+
518
+ print(f"Today is {hToday!r} ({WeekdayNames('en', hToday.dayofweek).name()}), "
519
+ f"{HebrewMonthNames('en', hToday.year, hToday.month).name()} {hToday.day}, {hToday.year}")
520
+ print()
521
+
522
+ year = hToday.year
523
+ months = list(range(HebrewMonth.TISHREI, HebrewDate.numMonthInYear(year) + 1))
524
+ months += list(range(HebrewMonth.NISAN, HebrewMonth.TISHREI))
525
+
526
+ for month in months:
527
+ cal = HebrewMonthCalendar(year, month)
528
+ print(f"{HebrewMonthNames('en', year, month).name()} {year}".center(28))
529
+ print("".join(f"{WeekdayNames('en', d).shortname():>4}" for d in range(1, 8)))
530
+ for row in cal.dates:
531
+ line = "".join(f"{cell.day:>4}" if cell else " " for cell in row)
532
+ shabbat = row[6]
533
+ if shabbat:
534
+ labels = []
535
+ if shabbat.shabbatType is not None:
536
+ labels.append(ShabbatTypeNames('en', shabbat.shabbatType).name())
537
+ if shabbat.shabbatChodeshType is not None:
538
+ labels.append(ShabbatChodeshTypeNames('en', shabbat.shabbatChodeshType).name())
539
+ if labels:
540
+ line += " " + ", ".join(labels)
541
+ print(line)
542
+ print()