-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathJewishDate.java
More file actions
1586 lines (1466 loc) · 60.1 KB
/
JewishDate.java
File metadata and controls
1586 lines (1466 loc) · 60.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Zmanim Java API
* Copyright (C) 2011 - 2024 Eliyahu Hershfeld
* Copyright (C) September 2002 Avrom Finkelstien
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA,
* or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
*/
package com.kosherjava.zmanim.hebrewcalendar;
import java.time.LocalDate;
import java.util.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
/**
* The JewishDate is the base calendar class, that supports maintenance of a {@link java.util.GregorianCalendar}
* instance along with the corresponding Jewish date. This class can use the standard Java Date and Calendar
* classes for setting and maintaining the dates, but it does not subclass these classes or use them internally
* in any calculations. This class also does not have a concept of a time (which the Date class does). Please
* note that the calendar does not currently support dates prior to 1/1/1 Gregorian. Also keep in mind that the
* Gregorian calendar started on October 15, 1582, so any calculations prior to that are suspect (at least from
* a Gregorian perspective). While 1/1/1 Gregorian and forward are technically supported, any calculations prior to <a
* href="http://en.wikipedia.org/wiki/Hillel_II">Hillel II's (Hakatan's</a>) calendar (4119 in the Jewish Calendar / 359
* CE Julian as recorded by <a href="http://en.wikipedia.org/wiki/Hai_Gaon">Rav Hai Gaon</a>) would be just an
* approximation.
*
* This open source Java code was written by <a href="http://www.facebook.com/avromf">Avrom Finkelstien</a> from his C++
* code. It was refactored to fit the KosherJava Zmanim API with simplification of the code, enhancements and some bug
* fixing.
*
* Some of Avrom's original C++ code was translated from
* <a href="https://web.archive.org/web/20120124134148/http://emr.cs.uiuc.edu/~reingold/calendar.C">C/C++ code</a> in
* <a href="http://www.calendarists.com">Calendrical Calculations</a> by Nachum Dershowitz and Edward M.
* Reingold, Software-- Practice & Experience, vol. 20, no. 9 (September, 1990), pp. 899- 928. Any method with the mark
* "ND+ER" indicates that the method was taken from this source with minor modifications.
*
* If you are looking for a class that implements a Jewish calendar version of the Calendar class, one is available from
* the <a href="http://site.icu-project.org/" >ICU (International Components for Unicode)</a> project, formerly part of
* IBM's DeveloperWorks.
*
* @see JewishCalendar
* @see HebrewDateFormatter
* @see java.util.Date
* @see java.util.Calendar
* @author © Avrom Finkelstien 2002
* @author © Eliyahu Hershfeld 2011 - 2024
*/
public class JewishDate implements Comparable<JewishDate>, Cloneable {
/**
* Value of the month field indicating Nissan, the first numeric month of the year in the Jewish calendar. With the
* year starting at {@link #TISHREI}, it would actually be the 7th (or 8th in a {@link #isJewishLeapYear() leap
* year}) month of the year.
*/
public static final int NISSAN = 1;
/**
* Value of the month field indicating Iyar, the second numeric month of the year in the Jewish calendar. With the
* year starting at {@link #TISHREI}, it would actually be the 8th (or 9th in a {@link #isJewishLeapYear() leap
* year}) month of the year.
*/
public static final int IYAR = 2;
/**
* Value of the month field indicating Sivan, the third numeric month of the year in the Jewish calendar. With the
* year starting at {@link #TISHREI}, it would actually be the 9th (or 10th in a {@link #isJewishLeapYear() leap
* year}) month of the year.
*/
public static final int SIVAN = 3;
/**
* Value of the month field indicating Tammuz, the fourth numeric month of the year in the Jewish calendar. With the
* year starting at {@link #TISHREI}, it would actually be the 10th (or 11th in a {@link #isJewishLeapYear() leap
* year}) month of the year.
*/
public static final int TAMMUZ = 4;
/**
* Value of the month field indicating Av, the fifth numeric month of the year in the Jewish calendar. With the year
* starting at {@link #TISHREI}, it would actually be the 11th (or 12th in a {@link #isJewishLeapYear() leap year})
* month of the year.
*/
public static final int AV = 5;
/**
* Value of the month field indicating Elul, the sixth numeric month of the year in the Jewish calendar. With the
* year starting at {@link #TISHREI}, it would actually be the 12th (or 13th in a {@link #isJewishLeapYear() leap
* year}) month of the year.
*/
public static final int ELUL = 6;
/**
* Value of the month field indicating Tishrei, the seventh numeric month of the year in the Jewish calendar. With
* the year starting at this month, it would actually be the 1st month of the year.
*/
public static final int TISHREI = 7;
/**
* Value of the month field indicating Cheshvan/marcheshvan, the eighth numeric month of the year in the Jewish
* calendar. With the year starting at {@link #TISHREI}, it would actually be the 2nd month of the year.
*/
public static final int CHESHVAN = 8;
/**
* Value of the month field indicating Kislev, the ninth numeric month of the year in the Jewish calendar. With the
* year starting at {@link #TISHREI}, it would actually be the 3rd month of the year.
*/
public static final int KISLEV = 9;
/**
* Value of the month field indicating Teves, the tenth numeric month of the year in the Jewish calendar. With the
* year starting at {@link #TISHREI}, it would actually be the 4th month of the year.
*/
public static final int TEVES = 10;
/**
* Value of the month field indicating Shevat, the eleventh numeric month of the year in the Jewish calendar. With
* the year starting at {@link #TISHREI}, it would actually be the 5th month of the year.
*/
public static final int SHEVAT = 11;
/**
* Value of the month field indicating Adar (or Adar I in a {@link #isJewishLeapYear() leap year}), the twelfth
* numeric month of the year in the Jewish calendar. With the year starting at {@link #TISHREI}, it would actually
* be the 6th month of the year.
*/
public static final int ADAR = 12;
/**
* Value of the month field indicating Adar II, the leap (intercalary or embolismic) thirteenth (Undecimber) numeric
* month of the year added in Jewish {@link #isJewishLeapYear() leap year}). The leap years are years 3, 6, 8, 11,
* 14, 17 and 19 of a 19-year cycle. With the year starting at {@link #TISHREI}, it would actually be the 7th month
* of the year.
*/
public static final int ADAR_II = 13;
/**
* the Jewish epoch using the RD (Rata Die/Fixed Date or Reingold Dershowitz) day used in Calendrical Calculations.
* Day 1 is January 1, 0001 of the Gregorian calendar
*/
private static final int JEWISH_EPOCH = -1373429;
/** The number of <em>chalakim</em> (18) in a minute.*/
private static final int CHALAKIM_PER_MINUTE = 18;
/** The number of <em>chalakim</em> (1080) in an hour.*/
private static final int CHALAKIM_PER_HOUR = 1080;
/** The number of <em>chalakim</em> (25,920) in a 24-hour day .*/
private static final int CHALAKIM_PER_DAY = 25920; // 24 * 1080
/** The number of <em>chalakim</em> in an average Jewish month. A month has 29 days, 12 hours and 793
* <em>chalakim</em> (44 minutes and 3.3 seconds) for a total of 765,433 <em>chalakim</em>*/
private static final long CHALAKIM_PER_MONTH = 765433; // (29 * 24 + 12) * 1080 + 793
/**
* Days from the beginning of Sunday till <em>molad BaHaRaD</em>. Calculated as 1 day, 5 hours and 204 <em>chalakim</em> =
* (24 + 5) * 1080 + 204 = 31524
*/
private static final int CHALAKIM_MOLAD_TOHU = 31524;
/**
* A short year where both {@link #CHESHVAN} and {@link #KISLEV} are 29 days.
*
* @see #getCheshvanKislevKviah()
* @see HebrewDateFormatter#getFormattedKviah(int)
*/
public static final int CHASERIM = 0;
/**
* An ordered year where {@link #CHESHVAN} is 29 days and {@link #KISLEV} is 30 days.
*
* @see #getCheshvanKislevKviah()
* @see HebrewDateFormatter#getFormattedKviah(int)
*/
public static final int KESIDRAN = 1;
/**
* A long year where both {@link #CHESHVAN} and {@link #KISLEV} are 30 days.
*
* @see #getCheshvanKislevKviah()
* @see HebrewDateFormatter#getFormattedKviah(int)
*/
public static final int SHELAIMIM = 2;
/** the internal Jewish month.*/
private int jewishMonth;
/** the internal Jewish day.*/
private int jewishDay;
/** the internal Jewish year.*/
private int jewishYear;
/** the internal count of <em>molad</em> hours.*/
private int moladHours;
/** the internal count of <em>molad</em> minutes.*/
private int moladMinutes;
/** the internal count of <em>molad chalakim</em>.*/
private int moladChalakim;
/**
* Returns the <em>molad</em> hours. Only a JewishDate object populated with {@link #getMolad()},
* {@link #setJewishDate(int, int, int, int, int, int)} or {@link #setMoladHours(int)} will have this field
* populated. A regular JewishDate object will have this field set to 0.
*
* @return the <em>molad</em> hours
* @see #setMoladHours(int)
* @see #getMolad()
* @see #setJewishDate(int, int, int, int, int, int)
*/
public int getMoladHours() {
return moladHours;
}
/**
* Sets the <em>molad</em> hours.
*
* @param moladHours
* the <em>molad</em> hours to set
* @see #getMoladHours()
* @see #getMolad()
* @see #setJewishDate(int, int, int, int, int, int)
*
*/
public void setMoladHours(int moladHours) {
this.moladHours = moladHours;
}
/**
* Returns the <em>molad</em> minutes. Only an object populated with {@link #getMolad()},
* {@link #setJewishDate(int, int, int, int, int, int)} or or {@link #setMoladMinutes(int)} will have these fields
* populated. A regular JewishDate object will have this field set to 0.
*
* @return the <em>molad</em> minutes
* @see #setMoladMinutes(int)
* @see #getMolad()
* @see #setJewishDate(int, int, int, int, int, int)
*/
public int getMoladMinutes() {
return moladMinutes;
}
/**
* Sets the <em>molad</em> minutes. The expectation is that the traditional minute-less <em>chalakim</em> will be broken out to
* minutes and {@link #setMoladChalakim(int) <em>chalakim</em> / parts} , so 793 (TaShTZaG) parts would have the minutes set to
* 44 and <em>chalakim</em> to 1.
*
* @param moladMinutes
* the molad minutes to set
* @see #getMoladMinutes()
* @see #setMoladChalakim(int)
* @see #getMolad()
* @see #setJewishDate(int, int, int, int, int, int)
*
*/
public void setMoladMinutes(int moladMinutes) {
this.moladMinutes = moladMinutes;
}
/**
* Sets the <em>molad</em> chalakim/parts. The expectation is that the traditional minute-less <em>chalakim</em> will be broken
* out to {@link #setMoladMinutes(int) minutes} and chalakim, so 793 (TaShTZaG) parts would have the minutes set to 44 and
* <em>chalakim</em> to 1.
*
* @param moladChalakim
* the <em>molad chalakim</em> / parts to set
* @see #getMoladChalakim()
* @see #setMoladMinutes(int)
* @see #getMolad()
* @see #setJewishDate(int, int, int, int, int, int)
*
*/
public void setMoladChalakim(int moladChalakim) {
this.moladChalakim = moladChalakim;
}
/**
* Returns the <em>molad chalakim</em> / parts. Only an object populated with {@link #getMolad()},
* {@link #setJewishDate(int, int, int, int, int, int)} or or {@link #setMoladChalakim(int)} will have these fields
* populated. A regular JewishDate object will have this field set to 0.
*
* @return the <em>molad chalakim</em> / parts
* @see #setMoladChalakim(int)
* @see #getMolad()
* @see #setJewishDate(int, int, int, int, int, int)
*/
public int getMoladChalakim() {
return moladChalakim;
}
/**
* Returns the last day in a gregorian month
*
* @param month
* the Gregorian month
* @return the last day of the Gregorian month
*/
int getLastDayOfGregorianMonth(int month) {
return getLastDayOfGregorianMonth(month, gregorianYear);
}
/**
* Returns is the year passed in is a <a href=
* "https://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar">Gregorian leap year</a>.
* @param year the Gregorian year
* @return if the year in question is a leap year.
*/
boolean isGregorianLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
/**
* The month, where 1 == January, 2 == February, etc... Note that this is different than Java's Calendar class
* where January == 0.
*/
private int gregorianMonth;
/** The day of the Gregorian month */
private int gregorianDayOfMonth;
/** The Gregorian year */
private int gregorianYear;
/** 1 == Sunday, 2 == Monday, etc... */
private int dayOfWeek;
/** Returns the absolute date (days since January 1, 0001 of the Gregorian calendar).
* @see #getAbsDate()
* @see #absDateToJewishDate()
*/
private int gregorianAbsDate;
/**
* Returns the number of days in a given month in a given month and year.
*
* @param month
* the month. As with other cases in this class, this is 1-based, not zero-based.
* @param year
* the year (only impacts February)
* @return the number of days in the month in the given year
*/
private static int getLastDayOfGregorianMonth(int month, int year) {
switch (month) {
case 2:
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
return 29;
} else {
return 28;
}
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
/**
* Computes the Gregorian date from the absolute date. ND+ER
* @param absDate the absolute date
*/
private void absDateToDate(int absDate) {
int year = absDate / 366; // Search forward year by year from approximate year
while (absDate >= gregorianDateToAbsDate(year + 1, 1, 1)) {
year++;
}
int month = 1; // Search forward month by month from January
while (absDate > gregorianDateToAbsDate(year, month, getLastDayOfGregorianMonth(month, year))) {
month++;
}
int dayOfMonth = absDate - gregorianDateToAbsDate(year, month, 1) + 1;
setInternalGregorianDate(year, month, dayOfMonth);
}
/**
* Returns the absolute date (days since January 1, 0001 of the Gregorian calendar).
*
* @return the number of days since January 1, 1
*/
public int getAbsDate() {
return gregorianAbsDate;
}
/**
* Computes the absolute date from a Gregorian date. ND+ER
*
* @param year
* the Gregorian year
* @param month
* the Gregorian month. Unlike the Java Calendar where January has the value of 0,This expects a 1 for
* January
* @param dayOfMonth
* the day of the month (1st, 2nd, etc...)
* @return the absolute Gregorian day
*/
private static int gregorianDateToAbsDate(int year, int month, int dayOfMonth) {
int absDate = dayOfMonth;
for (int m = month - 1; m > 0; m--) {
absDate += getLastDayOfGregorianMonth(m, year); // days in prior months of the year
}
return (absDate // days this year
+ 365 * (year - 1) // days in previous years ignoring leap days
+ (year - 1) / 4 // Julian leap days before this year
- (year - 1) / 100 // minus prior century years
+ (year - 1) / 400); // plus prior years divisible by 400
}
/**
* Returns if the year is a Jewish leap year. Years 3, 6, 8, 11, 14, 17 and 19 in the 19-year cycle are leap years.
*
* @param year
* the Jewish year.
* @return true if it is a leap year
* @see #isJewishLeapYear()
*/
private static boolean isJewishLeapYear(int year) {
return ((7 * year) + 1) % 19 < 7;
}
/**
* Returns if the year the calendar is set to is a Jewish leap year. Years 3, 6, 8, 11, 14, 17 and 19 in the 19-year
* cycle are leap years.
*
* @return true if it is a leap year
* @see #isJewishLeapYear(int)
*/
public boolean isJewishLeapYear() {
return isJewishLeapYear(getJewishYear());
}
/**
* Returns the last month of a given Jewish year. This will be 12 on a non {@link #isJewishLeapYear(int) leap year}
* or 13 on a leap year.
*
* @param year
* the Jewish year.
* @return 12 on a non leap year or 13 on a leap year
* @see #isJewishLeapYear(int)
*/
private static int getLastMonthOfJewishYear(int year) {
return isJewishLeapYear(year) ? ADAR_II : ADAR;
}
/**
* Returns the number of days elapsed from the Sunday prior to the start of the Jewish calendar to the mean
* conjunction of Tishri of the Jewish year.
*
* @param year
* the Jewish year
* @return the number of days elapsed from prior to the <em>molad Tohu BaHaRaD</em> (Be = Monday, <em>Ha</em> = 5
* hours and <em>RaD</em> = 204 <em>chalakim</em> / parts) prior to the start of the Jewish calendar, to
* the mean conjunction of Tishri of the Jewish year. BeHaRaD is 23:11:20 on Sunday night(5 hours 204/1080
* <em>chalakim</em> after sunset on Sunday evening).
*/
public static int getJewishCalendarElapsedDays(int year) {
long chalakimSince = getChalakimSinceMoladTohu(year, TISHREI);
int moladDay = (int) (chalakimSince / (long) CHALAKIM_PER_DAY);
int moladParts = (int) (chalakimSince - moladDay * (long) CHALAKIM_PER_DAY);
// delay Rosh Hashana for the 4 dechiyos
return addDechiyos(year, moladDay, moladParts);
}
/**
* Adds the 4 dechiyos for <em>molad</em> Tishrei. These are:
* <ol>
* <li><em>Lo ADU Rosh</em> - Rosh Hashana can't fall on a Sunday, Wednesday or Friday. If the <em>molad</em> fell on one
* of these days, Rosh Hashana is delayed to the following day.</li>
* <li><em>Molad Zaken</em> - If the <em>molad</em> of Tishrei falls after 12 noon, Rosh Hashana is delayed to the following
* day. If the following day is <em>ADU</em>, it will be delayed an additional day.</li>
* <li><em>GaTRaD</em> - If on a non leap year the <em>molad</em> of Tishrei falls on a Tuesday (Ga) on or after 9 hours
* (<em>T</em>) and (<em>RaD</em> 204 <em>chalakim</em> it is delayed till Thursday (one day delay, plus one day for
* <em>Lo ADU Rosh</em>)</li>
* <li><em>BeTuTaKPaT</em> - if the year following a leap year falls on a Monday (<em>Be</em>) on or after 15 hours
* (<em>Tu</em>) and 589 <em>chalakim</em> (<em>TaKPaT</em>) it is delayed till Tuesday</li>
* </ol>
*
* @param year the year
* @param moladDay the <em>molad</em> day
* @param moladParts the <em>molad</em> parts
* @return the number of elapsed days in the JewishCalendar adjusted for the 4 dechiyos.
*/
private static int addDechiyos(int year, int moladDay, int moladParts) {
int roshHashanaDay = moladDay; // if no dechiyos
// delay Rosh Hashana for the dechiyos of the Molad - new moon 1 - Molad Zaken, 2- GaTRaD 3- BeTuTaKPaT
if ((moladParts >= 19440) // Dechiya of Molad Zaken - molad is >= midday (18 hours * 1080 chalakim)
|| (((moladDay % 7) == 2) // start Dechiya of GaTRaD - Ga = is a Tuesday
&& (moladParts >= 9924) // TRaD = 9 hours, 204 parts or later (9 * 1080 + 204)
&& !isJewishLeapYear(year)) // of a non-leap year - end Dechiya of GaTRaD
|| (((moladDay % 7) == 1) // start Dechiya of BeTuTaKPaT - Be = is on a Monday
&& (moladParts >= 16789) // TUTaKPaT part of BeTuTaKPaT = 15 hours, 589 parts or later (15 * 1080 + 589)
&& (isJewishLeapYear(year - 1)))) { // in a year following a leap year - end Dechiya of BeTuTaKPaT
roshHashanaDay += 1; // Then postpone Rosh HaShanah one day
}
// start 4th Dechiya - Lo ADU Rosh - Rosh Hashana can't occur on A- sunday, D- Wednesday, U - Friday
if (((roshHashanaDay % 7) == 0)// If Rosh HaShanah would occur on Sunday,
|| ((roshHashanaDay % 7) == 3) // or Wednesday,
|| ((roshHashanaDay % 7) == 5)) { // or Friday - end 4th Dechiya - Lo ADU Rosh
roshHashanaDay = roshHashanaDay + 1; // Then postpone it one (more) day
}
return roshHashanaDay;
}
/**
* Returns the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em>
* to the year and month passed in.
*
* @param year
* the Jewish year
* @param month
* the Jewish month the Jewish month, with the month numbers starting from Nissan. Use the JewishDate
* constants such as {@link JewishDate#TISHREI}.
* @return the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em>
*/
private static long getChalakimSinceMoladTohu(int year, int month) {
// Jewish lunar month = 29 days, 12 hours and 793 chalakim
// chalakim since Molad Tohu BeHaRaD - 1 day, 5 hours and 204 chalakim
int monthOfYear = getJewishMonthOfYear(year, month);
int monthsElapsed = (235 * ((year - 1) / 19)) // Months in complete 19-year lunar (Metonic) cycles so far
+ (12 * ((year - 1) % 19)) // Regular months in this cycle
+ ((7 * ((year - 1) % 19) + 1) / 19) // Leap months this cycle
+ (monthOfYear - 1); // add elapsed months till the start of the molad of the month
// return chalakim prior to BeHaRaD + number of chalakim since
return CHALAKIM_MOLAD_TOHU + (CHALAKIM_PER_MONTH * monthsElapsed);
}
/**
* Returns the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em>
* to the Jewish year and month that this Object is set to.
*
* @return the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em>
*/
public long getChalakimSinceMoladTohu() {
return getChalakimSinceMoladTohu(jewishYear, jewishMonth);
}
/**
* Converts the {@link JewishDate#NISSAN} based constants used by this class to numeric month starting from
* {@link JewishDate#TISHREI}. This is required for <em>molad</em> calculations.
*
* @param year
* The Jewish year
* @param month
* The Jewish Month
* @return the Jewish month of the year starting with Tishrei
*/
private static int getJewishMonthOfYear(int year, int month) {
boolean isLeapYear = isJewishLeapYear(year);
return (month + (isLeapYear ? 6 : 5)) % (isLeapYear ? 13 : 12) + 1;
}
/**
* Validates the components of a Jewish date for validity. It will throw an {@link IllegalArgumentException} if the Jewish
* date is earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a {@link #isJewishLeapYear(int)
* leap year}), the day of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 or > 59 or
* <em>chalakim</em> < 0 or > 17. For larger a larger number of <em>chalakim</em> such as 793 (TaShTzaG) break the
* <em>chalakim</em> into minutes (18 <em>chalakim</em> per minutes, so it would be 44 minutes and 1 <em>chelek</em> in the
* case of 793 / <em>TaShTzaG</em>).
*
* @param year
* the Jewish year to validate. It will reject any year <= 3761 (lower than the year 1 Gregorian).
* @param month
* the Jewish month to validate. It will reject a month < 1 or > 12 (or 13 on a leap year) .
* @param dayOfMonth
* the day of the Jewish month to validate. It will reject any value < 1 or > the number of days in the month
* for that year.
* @param hours
* the hours (for <em>molad</em> calculations). It will reject an hour < 0 or > 23
* @param minutes
* the minutes (for <em>molad</em> calculations). It will reject a minute < 0 or > 59
* @param chalakim
* the <em>chalakim</em> / parts (for <em>molad</em> calculations). It will reject a <em>chalakim</em> < 0 or >
* 17. For larger numbers such as 793 (<em>TaShTzaG</em>) break the <em>chalakim</em> into minutes (18 <em>chalakim</em>
* per minutes, so it would be 44 minutes and 1 <em>chelek</em> in the case of 793 / <em>TaShTzaG</em>)
*
* @throws IllegalArgumentException
* if a Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a leap year),
* the day of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 or > 59 or <em>chalakim</em>
* < 0 or > 17. For larger a larger number of <em>chalakim</em> such as 793 (<em>TaShTzaG</em>) break the
* <em>chalakim</em> into minutes (18 <em>chalakim</em> per minutes, so it would be 44 minutes and 1 <em>chelek</em>
* in the case of 793 (<em>TaShTzaG</em>).
*/
private static void validateJewishDate(int year, int month, int dayOfMonth, int hours, int minutes, int chalakim) {
if (month < NISSAN || month > getLastMonthOfJewishYear(year)) {
throw new IllegalArgumentException("The Jewish month has to be between 1 and 12 (or 13 on a leap year). "
+ month + " is invalid for the year " + year + ".");
}
int maxDaysInMonth = getDaysInJewishMonth(month, year);
if (dayOfMonth < 1 || dayOfMonth > maxDaysInMonth) {
throw new IllegalArgumentException("The Jewish day of month can't be < 1 or > " + maxDaysInMonth + ". " + dayOfMonth
+ " is invalid for the month " + month + " of the year " + year + ".");
}
// reject dates prior to 18 Teves, 3761 (1/1/1 AD). This restriction can be relaxed if the date coding is
// changed/corrected
if ((year < 3761) || (year == 3761 && (month >= TISHREI && month < TEVES))
|| (year == 3761 && month == TEVES && dayOfMonth < 18)) {
throw new IllegalArgumentException(
"A Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian) can't be set. " + year + ", " + month
+ ", " + dayOfMonth + " is invalid.");
}
if (hours < 0 || hours > 23) {
throw new IllegalArgumentException("Hours < 0 or > 23 can't be set. " + hours + " is invalid.");
}
if (minutes < 0 || minutes > 59) {
throw new IllegalArgumentException("Minutes < 0 or > 59 can't be set. " + minutes + " is invalid.");
}
if (chalakim < 0 || chalakim > 17) {
throw new IllegalArgumentException(
"Chalakim/parts < 0 or > 17 can't be set. "
+ chalakim
+ " is invalid. For larger numbers such as 793 (TaShTzaG) break the <em>chalakim</em> into minutes (18 chalakim per minutes, so it would be 44 minutes and 1 chelek in the case of 793 (TaShTzaG)");
}
}
/**
* Validates the components of a Gregorian date for validity. It will throw an {@link IllegalArgumentException} if a
* year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in.
*
* @param year
* the Gregorian year to validate. It will reject any year < 1.
* @param month
* the Gregorian month number to validate. It will enforce that the month is between 0 - 11 like a
* {@link GregorianCalendar}, where {@link Calendar#JANUARY} has a value of 0.
* @param dayOfMonth
* the day of the Gregorian month to validate. It will reject any value < 1, but will allow values > 31
* since calling methods will simply set it to the maximum for that month. TODO: check calling methods to
* see if there is any reason that the class needs days > the maximum.
* @throws IllegalArgumentException
* if a year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in
* @see #validateGregorianYear(int)
* @see #validateGregorianMonth(int)
* @see #validateGregorianDayOfMonth(int)
*/
private static void validateGregorianDate(int year, int month, int dayOfMonth) {
validateGregorianMonth(month);
validateGregorianDayOfMonth(dayOfMonth);
validateGregorianYear(year);
}
/**
* Validates a Gregorian month for validity.
*
* @param month
* the Gregorian month number to validate. It will enforce that the month is between 0 - 11 like a
* {@link GregorianCalendar}, where {@link Calendar#JANUARY} has a value of 0.
*/
private static void validateGregorianMonth(int month) {
if (month > 11 || month < 0) {
throw new IllegalArgumentException("The Gregorian month has to be between 0 - 11. " + month
+ " is invalid.");
}
}
/**
* Validates a Gregorian day of month for validity.
*
* @param dayOfMonth
* the day of the Gregorian month to validate. It will reject any value < 1, but will allow values > 31
* since calling methods will simply set it to the maximum for that month. TODO: check calling methods to
* see if there is any reason that the class needs days > the maximum.
*/
private static void validateGregorianDayOfMonth(int dayOfMonth) {
if (dayOfMonth <= 0) {
throw new IllegalArgumentException("The day of month can't be less than 1. " + dayOfMonth + " is invalid.");
}
}
/**
* Validates a Gregorian year for validity.
*
* @param year
* the Gregorian year to validate. It will reject any year < 1.
*/
private static void validateGregorianYear(int year) {
if (year < 1) {
throw new IllegalArgumentException("Years < 1 can't be calculated. " + year + " is invalid.");
}
}
/**
* Returns the number of days for a given Jewish year. ND+ER
*
* @param year
* the Jewish year
* @return the number of days for a given Jewish year.
* @see #isCheshvanLong()
* @see #isKislevShort()
*/
public static int getDaysInJewishYear(int year) {
return getJewishCalendarElapsedDays(year + 1) - getJewishCalendarElapsedDays(year);
}
/**
* Returns the number of days for the current year that the calendar is set to.
*
* @return the number of days for the Object's current Jewish year.
* @see #isCheshvanLong()
* @see #isKislevShort()
* @see #isJewishLeapYear()
*/
public int getDaysInJewishYear() {
return getDaysInJewishYear(getJewishYear());
}
/**
* Returns if Cheshvan is long in a given Jewish year. The method name isLong is done since in a Kesidran (ordered)
* year Cheshvan is short. ND+ER
*
* @param year
* the year
* @return true if Cheshvan is long in Jewish year.
* @see #isCheshvanLong()
* @see #getCheshvanKislevKviah()
*/
private static boolean isCheshvanLong(int year) {
return getDaysInJewishYear(year) % 10 == 5;
}
/**
* Returns if Cheshvan is long (30 days VS 29 days) for the current year that the calendar is set to. The method
* name isLong is done since in a Kesidran (ordered) year Cheshvan is short.
*
* @return true if Cheshvan is long for the current year that the calendar is set to
* @see #isCheshvanLong()
*/
public boolean isCheshvanLong() {
return isCheshvanLong(getJewishYear());
}
/**
* Returns if Kislev is short (29 days VS 30 days) in a given Jewish year. The method name isShort is done since in
* a Kesidran (ordered) year Kislev is long. ND+ER
*
* @param year
* the Jewish year
* @return true if Kislev is short for the given Jewish year.
* @see #isKislevShort()
* @see #getCheshvanKislevKviah()
*/
private static boolean isKislevShort(int year) {
return getDaysInJewishYear(year) % 10 == 3;
}
/**
* Returns if the Kislev is short for the year that this class is set to. The method name isShort is done since in a
* Kesidran (ordered) year Kislev is long.
*
* @return true if Kislev is short for the year that this class is set to
*/
public boolean isKislevShort() {
return isKislevShort(getJewishYear());
}
/**
* Returns the Cheshvan and Kislev kviah (whether a Jewish year is short, regular or long). It will return
* {@link #SHELAIMIM} if both cheshvan and kislev are 30 days, {@link #KESIDRAN} if Cheshvan is 29 days and Kislev
* is 30 days and {@link #CHASERIM} if both are 29 days.
*
* @return {@link #SHELAIMIM} if both cheshvan and kislev are 30 days, {@link #KESIDRAN} if Cheshvan is 29 days and
* Kislev is 30 days and {@link #CHASERIM} if both are 29 days.
* @see #isCheshvanLong()
* @see #isKislevShort()
*/
public int getCheshvanKislevKviah() {
if (isCheshvanLong() && !isKislevShort()) {
return SHELAIMIM;
} else if (!isCheshvanLong() && isKislevShort()) {
return CHASERIM;
} else {
return KESIDRAN;
}
}
/**
* Returns the number of days of a Jewish month for a given month and year.
*
* @param month
* the Jewish month
* @param year
* the Jewish Year
* @return the number of days for a given Jewish month
*/
private static int getDaysInJewishMonth(int month, int year) {
if ((month == IYAR) || (month == TAMMUZ) || (month == ELUL) || ((month == CHESHVAN) && !(isCheshvanLong(year)))
|| ((month == KISLEV) && isKislevShort(year)) || (month == TEVES)
|| ((month == ADAR) && !(isJewishLeapYear(year))) || (month == ADAR_II)) {
return 29;
} else {
return 30;
}
}
/**
* Returns the number of days of the Jewish month that the calendar is currently set to.
*
* @return the number of days for the Jewish month that the calendar is currently set to.
*/
public int getDaysInJewishMonth() {
return getDaysInJewishMonth(getJewishMonth(), getJewishYear());
}
/**
* Computes the Jewish date from the absolute date.
*/
private void absDateToJewishDate() {
// Approximation from below
jewishYear = (gregorianAbsDate - JEWISH_EPOCH) / 366;
// Search forward for year from the approximation
while (gregorianAbsDate >= jewishDateToAbsDate(jewishYear + 1, TISHREI, 1)) {
jewishYear++;
}
// Search forward for month from either Tishri or Nissan.
if (gregorianAbsDate < jewishDateToAbsDate(jewishYear, NISSAN, 1)) {
jewishMonth = TISHREI;// Start at Tishri
} else {
jewishMonth = NISSAN;// Start at Nissan
}
while (gregorianAbsDate > jewishDateToAbsDate(jewishYear, jewishMonth, getDaysInJewishMonth())) {
jewishMonth++;
}
// Calculate the day by subtraction
jewishDay = gregorianAbsDate - jewishDateToAbsDate(jewishYear, jewishMonth, 1) + 1;
}
/**
* Returns the absolute date of Jewish date. ND+ER
*
* @param year
* the Jewish year. The year can't be negative
* @param month
* the Jewish month starting with Nissan. Nissan expects a value of 1 etc. until Adar with a value of 12.
* For a leap year, 13 will be the expected value for Adar II. Use the constants {@link JewishDate#NISSAN}
* etc.
* @param dayOfMonth
* the Jewish day of month. valid values are 1-30. If the day of month is set to 30 for a month that only
* has 29 days, the day will be set as 29.
* @return the absolute date of the Jewish date.
*/
private static int jewishDateToAbsDate(int year, int month, int dayOfMonth) {
int elapsed = getDaysSinceStartOfJewishYear(year, month, dayOfMonth);
// add elapsed days this year + Days in prior years + Days elapsed before absolute year 1
return elapsed + getJewishCalendarElapsedDays(year) + JEWISH_EPOCH;
}
/**
* Returns the <em>molad</em> for a given year and month. Returns a JewishDate {@link Object} set to the date of the <em>molad</em>
* with the {@link #getMoladHours() hours}, {@link #getMoladMinutes() minutes} and {@link #getMoladChalakim()
* chalakim} set. In the current implementation, it sets the <em>molad</em> time based on a midnight date rollover. This
* means that Rosh Chodesh Adar II, 5771 with a <em>molad</em> of 7 <em>chalakim</em> past midnight on Shabbos 29 Adar I / March 5,
* 2011 12:00 AM and 7 chalakim, will have the following values: hours: 0, minutes: 0, Chalakim: 7.
*
* @return a JewishDate {@link Object} set to the date of the <em>molad</em> with the {@link #getMoladHours() hours},
* {@link #getMoladMinutes() minutes} and {@link #getMoladChalakim() <em>chalakim</em>} set.
*/
public JewishDate getMolad() {
JewishDate moladDate = new JewishDate(getChalakimSinceMoladTohu());
if (moladDate.getMoladHours() >= 6) {
moladDate.forward(Calendar.DATE, 1);
}
moladDate.setMoladHours((moladDate.getMoladHours() + 18) % 24);
return moladDate;
}
/**
* Returns the number of days from the Jewish epoch from the number of <em>chalakim</em> from the epoch passed in.
*
* @param chalakim
* the number of <em>chalakim</em> since the beginning of Sunday prior to BaHaRaD
* @return the number of days from the Jewish epoch
*/
private static int moladToAbsDate(long chalakim) {
return (int) (chalakim / CHALAKIM_PER_DAY) + JEWISH_EPOCH;
}
/**
* Constructor that creates a JewishDate based on a <em>molad</em> passed in. The <em>molad</em> would be the number of
* <em>chalakim</em> / parts starting at the beginning of Sunday prior to the <em>Molad Tohu BeHaRaD</em> (<em>Be</em> =
* Monday, <em>Ha</em> = 5 hours and <em>RaD</em> = 204 <em>chalakim</em> / parts) - prior to the start of the Jewish
* calendar. <em>BeHaRaD</em> is 23:11:20 on Sunday night(5 hours 204/1080 <em>chalakim</em> after sunset on Sunday evening).
*
* @param molad the number of <em>chalakim</em> since the beginning of Sunday prior to BaHaRaD
*/
public JewishDate(long molad) {
absDateToDate(moladToAbsDate(molad));
int conjunctionDay = (int) (molad / (long) CHALAKIM_PER_DAY);
int conjunctionParts = (int) (molad - conjunctionDay * (long) CHALAKIM_PER_DAY);
setMoladTime(conjunctionParts);
}
/**
* Sets the <em>molad</em> time (hours minutes and chalakim) based on the number of <em>chalakim</em> since the start of the day.
*
* @param chalakim
* the number of <em>chalakim</em> since the start of the day.
*/
private void setMoladTime(int chalakim) {
int adjustedChalakim = chalakim;
setMoladHours(adjustedChalakim / CHALAKIM_PER_HOUR);
adjustedChalakim = adjustedChalakim - (getMoladHours() * CHALAKIM_PER_HOUR);
setMoladMinutes(adjustedChalakim / CHALAKIM_PER_MINUTE);
setMoladChalakim(adjustedChalakim - moladMinutes * CHALAKIM_PER_MINUTE);
}
/**
* returns the number of days from Rosh Hashana of the date passed in, to the full date passed in.
*
* @param year
* the Jewish year
* @param month
* the Jewish month
* @param dayOfMonth
* the day in the Jewish month
* @return the number of days
*/
private static int getDaysSinceStartOfJewishYear(int year, int month, int dayOfMonth) {
int elapsedDays = dayOfMonth;
// Before Tishrei (from Nissan to Tishrei), add days in prior months
if (month < TISHREI) {
// this year before and after Nissan.
for (int m = TISHREI; m <= getLastMonthOfJewishYear(year); m++) {
elapsedDays += getDaysInJewishMonth(m, year);
}
for (int m = NISSAN; m < month; m++) {
elapsedDays += getDaysInJewishMonth(m, year);
}
} else { // Add days in prior months this year
for (int m = TISHREI; m < month; m++) {
elapsedDays += getDaysInJewishMonth(m, year);
}
}
return elapsedDays;
}
/**
* returns the number of days from Rosh Hashana of the date passed in, to the full date passed in.
*
* @return the number of days
*/
public int getDaysSinceStartOfJewishYear() {
return getDaysSinceStartOfJewishYear(getJewishYear(), getJewishMonth(), getJewishDayOfMonth());
}
/**
* Creates a Jewish date based on a Jewish year, month and day of month.
*
* @param jewishYear
* the Jewish year
* @param jewishMonth
* the Jewish month. The method expects a 1 for Nissan ... 12 for Adar and 13 for Adar II. Use the
* constants {@link #NISSAN} ... {@link #ADAR} (or {@link #ADAR_II} for a leap year Adar II) to avoid any
* confusion.
* @param jewishDayOfMonth
* the Jewish day of month. If 30 is passed in for a month with only 29 days (for example {@link #IYAR},
* or {@link #KISLEV} in a year that {@link #isKislevShort()}), the 29th (last valid date of the month)
* will be set
* @throws IllegalArgumentException
* if the day of month is < 1 or > 30, or a year of < 0 is passed in.
*/
public JewishDate(int jewishYear, int jewishMonth, int jewishDayOfMonth) {
setJewishDate(jewishYear, jewishMonth, jewishDayOfMonth);
}
/**
* Default constructor will set a default date to the current system date.
*/
public JewishDate() {
resetDate();
}
/**
* A constructor that initializes the date to the {@link java.util.Date Date} parameter.
*
* @param date
* the <code>Date</code> to set the calendar to
* @throws IllegalArgumentException
* if the date would fall prior to the January 1, 1 AD
*/
public JewishDate(Date date) {
setDate(date);
}
/**
* A constructor that initializes the date to the {@link java.util.Calendar Calendar} parameter.
*
* @param calendar
* the <code>Calendar</code> to set the calendar to
* @throws IllegalArgumentException
* if the {@link Calendar#ERA} is {@link GregorianCalendar#BC}
*/
public JewishDate(Calendar calendar) {