001/* 002 * Zmanim Java API 003 * Copyright (C) 2011 - 2024 Eliyahu Hershfeld 004 * Copyright (C) September 2002 Avrom Finkelstien 005 * 006 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 007 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 008 * any later version. 009 * 010 * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 011 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 012 * details. 013 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 014 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 015 * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 016 */ 017package com.kosherjava.zmanim.hebrewcalendar; 018 019import java.time.LocalDate; 020import java.util.Date; 021import java.util.Calendar; 022import java.util.GregorianCalendar; 023 024/** 025 * The JewishDate is the base calendar class, that supports maintenance of a {@link java.util.GregorianCalendar} 026 * instance along with the corresponding Jewish date. This class can use the standard Java Date and Calendar 027 * classes for setting and maintaining the dates, but it does not subclass these classes or use them internally 028 * in any calculations. This class also does not have a concept of a time (which the Date class does). Please 029 * note that the calendar does not currently support dates prior to 1/1/1 Gregorian. Also keep in mind that the 030 * Gregorian calendar started on October 15, 1582, so any calculations prior to that are suspect (at least from 031 * a Gregorian perspective). While 1/1/1 Gregorian and forward are technically supported, any calculations prior to <a 032 * href="http://en.wikipedia.org/wiki/Hillel_II">Hillel II's (Hakatan's</a>) calendar (4119 in the Jewish Calendar / 359 033 * CE Julian as recorded by <a href="http://en.wikipedia.org/wiki/Hai_Gaon">Rav Hai Gaon</a>) would be just an 034 * approximation. 035 * 036 * This open source Java code was written by <a href="http://www.facebook.com/avromf">Avrom Finkelstien</a> from his C++ 037 * code. It was refactored to fit the KosherJava Zmanim API with simplification of the code, enhancements and some bug 038 * fixing. 039 * 040 * Some of Avrom's original C++ code was translated from 041 * <a href="https://web.archive.org/web/20120124134148/http://emr.cs.uiuc.edu/~reingold/calendar.C">C/C++ code</a> in 042 * <a href="http://www.calendarists.com">Calendrical Calculations</a> by Nachum Dershowitz and Edward M. 043 * Reingold, Software-- Practice & Experience, vol. 20, no. 9 (September, 1990), pp. 899- 928. Any method with the mark 044 * "ND+ER" indicates that the method was taken from this source with minor modifications. 045 * 046 * If you are looking for a class that implements a Jewish calendar version of the Calendar class, one is available from 047 * the <a href="http://site.icu-project.org/" >ICU (International Components for Unicode)</a> project, formerly part of 048 * IBM's DeveloperWorks. 049 * 050 * @see JewishCalendar 051 * @see HebrewDateFormatter 052 * @see java.util.Date 053 * @see java.util.Calendar 054 * @author © Avrom Finkelstien 2002 055 * @author © Eliyahu Hershfeld 2011 - 2024 056 */ 057public class JewishDate implements Comparable<JewishDate>, Cloneable { 058 /** 059 * Value of the month field indicating Nissan, the first numeric month of the year in the Jewish calendar. With the 060 * year starting at {@link #TISHREI}, it would actually be the 7th (or 8th in a {@link #isJewishLeapYear() leap 061 * year}) month of the year. 062 */ 063 public static final int NISSAN = 1; 064 065 /** 066 * Value of the month field indicating Iyar, the second numeric month of the year in the Jewish calendar. With the 067 * year starting at {@link #TISHREI}, it would actually be the 8th (or 9th in a {@link #isJewishLeapYear() leap 068 * year}) month of the year. 069 */ 070 public static final int IYAR = 2; 071 072 /** 073 * Value of the month field indicating Sivan, the third numeric month of the year in the Jewish calendar. With the 074 * year starting at {@link #TISHREI}, it would actually be the 9th (or 10th in a {@link #isJewishLeapYear() leap 075 * year}) month of the year. 076 */ 077 public static final int SIVAN = 3; 078 079 /** 080 * Value of the month field indicating Tammuz, the fourth numeric month of the year in the Jewish calendar. With the 081 * year starting at {@link #TISHREI}, it would actually be the 10th (or 11th in a {@link #isJewishLeapYear() leap 082 * year}) month of the year. 083 */ 084 public static final int TAMMUZ = 4; 085 086 /** 087 * Value of the month field indicating Av, the fifth numeric month of the year in the Jewish calendar. With the year 088 * starting at {@link #TISHREI}, it would actually be the 11th (or 12th in a {@link #isJewishLeapYear() leap year}) 089 * month of the year. 090 */ 091 public static final int AV = 5; 092 093 /** 094 * Value of the month field indicating Elul, the sixth numeric month of the year in the Jewish calendar. With the 095 * year starting at {@link #TISHREI}, it would actually be the 12th (or 13th in a {@link #isJewishLeapYear() leap 096 * year}) month of the year. 097 */ 098 public static final int ELUL = 6; 099 100 /** 101 * Value of the month field indicating Tishrei, the seventh numeric month of the year in the Jewish calendar. With 102 * the year starting at this month, it would actually be the 1st month of the year. 103 */ 104 public static final int TISHREI = 7; 105 106 /** 107 * Value of the month field indicating Cheshvan/marcheshvan, the eighth numeric month of the year in the Jewish 108 * calendar. With the year starting at {@link #TISHREI}, it would actually be the 2nd month of the year. 109 */ 110 public static final int CHESHVAN = 8; 111 112 /** 113 * Value of the month field indicating Kislev, the ninth numeric month of the year in the Jewish calendar. With the 114 * year starting at {@link #TISHREI}, it would actually be the 3rd month of the year. 115 */ 116 public static final int KISLEV = 9; 117 118 /** 119 * Value of the month field indicating Teves, the tenth numeric month of the year in the Jewish calendar. With the 120 * year starting at {@link #TISHREI}, it would actually be the 4th month of the year. 121 */ 122 public static final int TEVES = 10; 123 124 /** 125 * Value of the month field indicating Shevat, the eleventh numeric month of the year in the Jewish calendar. With 126 * the year starting at {@link #TISHREI}, it would actually be the 5th month of the year. 127 */ 128 public static final int SHEVAT = 11; 129 130 /** 131 * Value of the month field indicating Adar (or Adar I in a {@link #isJewishLeapYear() leap year}), the twelfth 132 * numeric month of the year in the Jewish calendar. With the year starting at {@link #TISHREI}, it would actually 133 * be the 6th month of the year. 134 */ 135 public static final int ADAR = 12; 136 137 /** 138 * Value of the month field indicating Adar II, the leap (intercalary or embolismic) thirteenth (Undecimber) numeric 139 * month of the year added in Jewish {@link #isJewishLeapYear() leap year}). The leap years are years 3, 6, 8, 11, 140 * 14, 17 and 19 of a 19-year cycle. With the year starting at {@link #TISHREI}, it would actually be the 7th month 141 * of the year. 142 */ 143 public static final int ADAR_II = 13; 144 145 /** 146 * the Jewish epoch using the RD (Rata Die/Fixed Date or Reingold Dershowitz) day used in Calendrical Calculations. 147 * Day 1 is January 1, 0001 of the Gregorian calendar 148 */ 149 private static final int JEWISH_EPOCH = -1373429; 150 151 /** The number of <em>chalakim</em> (18) in a minute.*/ 152 private static final int CHALAKIM_PER_MINUTE = 18; 153 /** The number of <em>chalakim</em> (1080) in an hour.*/ 154 private static final int CHALAKIM_PER_HOUR = 1080; 155 /** The number of <em>chalakim</em> (25,920) in a 24-hour day .*/ 156 private static final int CHALAKIM_PER_DAY = 25920; // 24 * 1080 157 /** The number of <em>chalakim</em> in an average Jewish month. A month has 29 days, 12 hours and 793 158 * <em>chalakim</em> (44 minutes and 3.3 seconds) for a total of 765,433 <em>chalakim</em>*/ 159 private static final long CHALAKIM_PER_MONTH = 765433; // (29 * 24 + 12) * 1080 + 793 160 /** 161 * Days from the beginning of Sunday till <em>molad BaHaRaD</em>. Calculated as 1 day, 5 hours and 204 <em>chalakim</em> = 162 * (24 + 5) * 1080 + 204 = 31524 163 */ 164 private static final int CHALAKIM_MOLAD_TOHU = 31524; 165 166 /** 167 * A short year where both {@link #CHESHVAN} and {@link #KISLEV} are 29 days. 168 * 169 * @see #getCheshvanKislevKviah() 170 * @see HebrewDateFormatter#getFormattedKviah(int) 171 */ 172 public static final int CHASERIM = 0; 173 174 /** 175 * An ordered year where {@link #CHESHVAN} is 29 days and {@link #KISLEV} is 30 days. 176 * 177 * @see #getCheshvanKislevKviah() 178 * @see HebrewDateFormatter#getFormattedKviah(int) 179 */ 180 public static final int KESIDRAN = 1; 181 182 /** 183 * A long year where both {@link #CHESHVAN} and {@link #KISLEV} are 30 days. 184 * 185 * @see #getCheshvanKislevKviah() 186 * @see HebrewDateFormatter#getFormattedKviah(int) 187 */ 188 public static final int SHELAIMIM = 2; 189 190 /** the internal Jewish month.*/ 191 private int jewishMonth; 192 /** the internal Jewish day.*/ 193 private int jewishDay; 194 /** the internal Jewish year.*/ 195 private int jewishYear; 196 /** the internal count of <em>molad</em> hours.*/ 197 private int moladHours; 198 /** the internal count of <em>molad</em> minutes.*/ 199 private int moladMinutes; 200 /** the internal count of <em>molad chalakim</em>.*/ 201 private int moladChalakim; 202 203 /** 204 * Returns the <em>molad</em> hours. Only a JewishDate object populated with {@link #getMolad()}, 205 * {@link #setJewishDate(int, int, int, int, int, int)} or {@link #setMoladHours(int)} will have this field 206 * populated. A regular JewishDate object will have this field set to 0. 207 * 208 * @return the <em>molad</em> hours 209 * @see #setMoladHours(int) 210 * @see #getMolad() 211 * @see #setJewishDate(int, int, int, int, int, int) 212 */ 213 public int getMoladHours() { 214 return moladHours; 215 } 216 217 /** 218 * Sets the <em>molad</em> hours. 219 * 220 * @param moladHours 221 * the <em>molad</em> hours to set 222 * @see #getMoladHours() 223 * @see #getMolad() 224 * @see #setJewishDate(int, int, int, int, int, int) 225 * 226 */ 227 public void setMoladHours(int moladHours) { 228 this.moladHours = moladHours; 229 } 230 231 /** 232 * Returns the <em>molad</em> minutes. Only an object populated with {@link #getMolad()}, 233 * {@link #setJewishDate(int, int, int, int, int, int)} or or {@link #setMoladMinutes(int)} will have these fields 234 * populated. A regular JewishDate object will have this field set to 0. 235 * 236 * @return the <em>molad</em> minutes 237 * @see #setMoladMinutes(int) 238 * @see #getMolad() 239 * @see #setJewishDate(int, int, int, int, int, int) 240 */ 241 public int getMoladMinutes() { 242 return moladMinutes; 243 } 244 245 /** 246 * Sets the <em>molad</em> minutes. The expectation is that the traditional minute-less <em>chalakim</em> will be broken out to 247 * minutes and {@link #setMoladChalakim(int) <em>chalakim</em> / parts} , so 793 (TaShTZaG) parts would have the minutes set to 248 * 44 and <em>chalakim</em> to 1. 249 * 250 * @param moladMinutes 251 * the molad minutes to set 252 * @see #getMoladMinutes() 253 * @see #setMoladChalakim(int) 254 * @see #getMolad() 255 * @see #setJewishDate(int, int, int, int, int, int) 256 * 257 */ 258 public void setMoladMinutes(int moladMinutes) { 259 this.moladMinutes = moladMinutes; 260 } 261 262 /** 263 * Sets the <em>molad</em> chalakim/parts. The expectation is that the traditional minute-less <em>chalakim</em> will be broken 264 * out to {@link #setMoladMinutes(int) minutes} and chalakim, so 793 (TaShTZaG) parts would have the minutes set to 44 and 265 * <em>chalakim</em> to 1. 266 * 267 * @param moladChalakim 268 * the <em>molad chalakim</em> / parts to set 269 * @see #getMoladChalakim() 270 * @see #setMoladMinutes(int) 271 * @see #getMolad() 272 * @see #setJewishDate(int, int, int, int, int, int) 273 * 274 */ 275 public void setMoladChalakim(int moladChalakim) { 276 this.moladChalakim = moladChalakim; 277 } 278 279 /** 280 * Returns the <em>molad chalakim</em> / parts. Only an object populated with {@link #getMolad()}, 281 * {@link #setJewishDate(int, int, int, int, int, int)} or or {@link #setMoladChalakim(int)} will have these fields 282 * populated. A regular JewishDate object will have this field set to 0. 283 * 284 * @return the <em>molad chalakim</em> / parts 285 * @see #setMoladChalakim(int) 286 * @see #getMolad() 287 * @see #setJewishDate(int, int, int, int, int, int) 288 */ 289 public int getMoladChalakim() { 290 return moladChalakim; 291 } 292 293 /** 294 * Returns the last day in a gregorian month 295 * 296 * @param month 297 * the Gregorian month 298 * @return the last day of the Gregorian month 299 */ 300 int getLastDayOfGregorianMonth(int month) { 301 return getLastDayOfGregorianMonth(month, gregorianYear); 302 } 303 304 /** 305 * Returns is the year passed in is a <a href= 306 * "https://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar">Gregorian leap year</a>. 307 * @param year the Gregorian year 308 * @return if the year in question is a leap year. 309 */ 310 boolean isGregorianLeapYear(int year) { 311 return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); 312 } 313 314 /** 315 * The month, where 1 == January, 2 == February, etc... Note that this is different than Java's Calendar class 316 * where January == 0. 317 */ 318 private int gregorianMonth; 319 320 /** The day of the Gregorian month */ 321 private int gregorianDayOfMonth; 322 323 /** The Gregorian year */ 324 private int gregorianYear; 325 326 /** 1 == Sunday, 2 == Monday, etc... */ 327 private int dayOfWeek; 328 329 /** Returns the absolute date (days since January 1, 0001 of the Gregorian calendar). 330 * @see #getAbsDate() 331 * @see #absDateToJewishDate() 332 */ 333 private int gregorianAbsDate; 334 335 /** 336 * Returns the number of days in a given month in a given month and year. 337 * 338 * @param month 339 * the month. As with other cases in this class, this is 1-based, not zero-based. 340 * @param year 341 * the year (only impacts February) 342 * @return the number of days in the month in the given year 343 */ 344 private static int getLastDayOfGregorianMonth(int month, int year) { 345 switch (month) { 346 case 2: 347 if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { 348 return 29; 349 } else { 350 return 28; 351 } 352 case 4: 353 case 6: 354 case 9: 355 case 11: 356 return 30; 357 default: 358 return 31; 359 } 360 } 361 362 /** 363 * Computes the Gregorian date from the absolute date. ND+ER 364 * @param absDate the absolute date 365 */ 366 private void absDateToDate(int absDate) { 367 int year = absDate / 366; // Search forward year by year from approximate year 368 while (absDate >= gregorianDateToAbsDate(year + 1, 1, 1)) { 369 year++; 370 } 371 372 int month = 1; // Search forward month by month from January 373 while (absDate > gregorianDateToAbsDate(year, month, getLastDayOfGregorianMonth(month, year))) { 374 month++; 375 } 376 377 int dayOfMonth = absDate - gregorianDateToAbsDate(year, month, 1) + 1; 378 setInternalGregorianDate(year, month, dayOfMonth); 379 } 380 381 /** 382 * Returns the absolute date (days since January 1, 0001 of the Gregorian calendar). 383 * 384 * @return the number of days since January 1, 1 385 */ 386 public int getAbsDate() { 387 return gregorianAbsDate; 388 } 389 390 /** 391 * Computes the absolute date from a Gregorian date. ND+ER 392 * 393 * @param year 394 * the Gregorian year 395 * @param month 396 * the Gregorian month. Unlike the Java Calendar where January has the value of 0,This expects a 1 for 397 * January 398 * @param dayOfMonth 399 * the day of the month (1st, 2nd, etc...) 400 * @return the absolute Gregorian day 401 */ 402 private static int gregorianDateToAbsDate(int year, int month, int dayOfMonth) { 403 int absDate = dayOfMonth; 404 for (int m = month - 1; m > 0; m--) { 405 absDate += getLastDayOfGregorianMonth(m, year); // days in prior months of the year 406 } 407 return (absDate // days this year 408 + 365 * (year - 1) // days in previous years ignoring leap days 409 + (year - 1) / 4 // Julian leap days before this year 410 - (year - 1) / 100 // minus prior century years 411 + (year - 1) / 400); // plus prior years divisible by 400 412 } 413 414 /** 415 * 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. 416 * 417 * @param year 418 * the Jewish year. 419 * @return true if it is a leap year 420 * @see #isJewishLeapYear() 421 */ 422 private static boolean isJewishLeapYear(int year) { 423 return ((7 * year) + 1) % 19 < 7; 424 } 425 426 /** 427 * 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 428 * cycle are leap years. 429 * 430 * @return true if it is a leap year 431 * @see #isJewishLeapYear(int) 432 */ 433 public boolean isJewishLeapYear() { 434 return isJewishLeapYear(getJewishYear()); 435 } 436 437 /** 438 * Returns the last month of a given Jewish year. This will be 12 on a non {@link #isJewishLeapYear(int) leap year} 439 * or 13 on a leap year. 440 * 441 * @param year 442 * the Jewish year. 443 * @return 12 on a non leap year or 13 on a leap year 444 * @see #isJewishLeapYear(int) 445 */ 446 private static int getLastMonthOfJewishYear(int year) { 447 return isJewishLeapYear(year) ? ADAR_II : ADAR; 448 } 449 450 /** 451 * Returns the number of days elapsed from the Sunday prior to the start of the Jewish calendar to the mean 452 * conjunction of Tishri of the Jewish year. 453 * 454 * @param year 455 * the Jewish year 456 * @return the number of days elapsed from prior to the <em>molad Tohu BaHaRaD</em> (Be = Monday, <em>Ha</em> = 5 457 * hours and <em>RaD</em> = 204 <em>chalakim</em> / parts) prior to the start of the Jewish calendar, to 458 * the mean conjunction of Tishri of the Jewish year. BeHaRaD is 23:11:20 on Sunday night(5 hours 204/1080 459 * <em>chalakim</em> after sunset on Sunday evening). 460 */ 461 public static int getJewishCalendarElapsedDays(int year) { 462 long chalakimSince = getChalakimSinceMoladTohu(year, TISHREI); 463 int moladDay = (int) (chalakimSince / (long) CHALAKIM_PER_DAY); 464 int moladParts = (int) (chalakimSince - moladDay * (long) CHALAKIM_PER_DAY); 465 // delay Rosh Hashana for the 4 dechiyos 466 return addDechiyos(year, moladDay, moladParts); 467 } 468 469 /** 470 * Adds the 4 dechiyos for <em>molad</em> Tishrei. These are: 471 * <ol> 472 * <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 473 * of these days, Rosh Hashana is delayed to the following day.</li> 474 * <li><em>Molad Zaken</em> - If the <em>molad</em> of Tishrei falls after 12 noon, Rosh Hashana is delayed to the following 475 * day. If the following day is <em>ADU</em>, it will be delayed an additional day.</li> 476 * <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 477 * (<em>T</em>) and (<em>RaD</em> 204 <em>chalakim</em> it is delayed till Thursday (one day delay, plus one day for 478 * <em>Lo ADU Rosh</em>)</li> 479 * <li><em>BeTuTaKPaT</em> - if the year following a leap year falls on a Monday (<em>Be</em>) on or after 15 hours 480 * (<em>Tu</em>) and 589 <em>chalakim</em> (<em>TaKPaT</em>) it is delayed till Tuesday</li> 481 * </ol> 482 * 483 * @param year the year 484 * @param moladDay the <em>molad</em> day 485 * @param moladParts the <em>molad</em> parts 486 * @return the number of elapsed days in the JewishCalendar adjusted for the 4 dechiyos. 487 */ 488 private static int addDechiyos(int year, int moladDay, int moladParts) { 489 int roshHashanaDay = moladDay; // if no dechiyos 490 // delay Rosh Hashana for the dechiyos of the Molad - new moon 1 - Molad Zaken, 2- GaTRaD 3- BeTuTaKPaT 491 if ((moladParts >= 19440) // Dechiya of Molad Zaken - molad is >= midday (18 hours * 1080 chalakim) 492 || (((moladDay % 7) == 2) // start Dechiya of GaTRaD - Ga = is a Tuesday 493 && (moladParts >= 9924) // TRaD = 9 hours, 204 parts or later (9 * 1080 + 204) 494 && !isJewishLeapYear(year)) // of a non-leap year - end Dechiya of GaTRaD 495 || (((moladDay % 7) == 1) // start Dechiya of BeTuTaKPaT - Be = is on a Monday 496 && (moladParts >= 16789) // TUTaKPaT part of BeTuTaKPaT = 15 hours, 589 parts or later (15 * 1080 + 589) 497 && (isJewishLeapYear(year - 1)))) { // in a year following a leap year - end Dechiya of BeTuTaKPaT 498 roshHashanaDay += 1; // Then postpone Rosh HaShanah one day 499 } 500 // start 4th Dechiya - Lo ADU Rosh - Rosh Hashana can't occur on A- sunday, D- Wednesday, U - Friday 501 if (((roshHashanaDay % 7) == 0)// If Rosh HaShanah would occur on Sunday, 502 || ((roshHashanaDay % 7) == 3) // or Wednesday, 503 || ((roshHashanaDay % 7) == 5)) { // or Friday - end 4th Dechiya - Lo ADU Rosh 504 roshHashanaDay = roshHashanaDay + 1; // Then postpone it one (more) day 505 } 506 return roshHashanaDay; 507 } 508 509 /** 510 * Returns the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em> 511 * to the year and month passed in. 512 * 513 * @param year 514 * the Jewish year 515 * @param month 516 * the Jewish month the Jewish month, with the month numbers starting from Nissan. Use the JewishDate 517 * constants such as {@link JewishDate#TISHREI}. 518 * @return the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em> 519 */ 520 private static long getChalakimSinceMoladTohu(int year, int month) { 521 // Jewish lunar month = 29 days, 12 hours and 793 chalakim 522 // chalakim since Molad Tohu BeHaRaD - 1 day, 5 hours and 204 chalakim 523 int monthOfYear = getJewishMonthOfYear(year, month); 524 int monthsElapsed = (235 * ((year - 1) / 19)) // Months in complete 19-year lunar (Metonic) cycles so far 525 + (12 * ((year - 1) % 19)) // Regular months in this cycle 526 + ((7 * ((year - 1) % 19) + 1) / 19) // Leap months this cycle 527 + (monthOfYear - 1); // add elapsed months till the start of the molad of the month 528 // return chalakim prior to BeHaRaD + number of chalakim since 529 return CHALAKIM_MOLAD_TOHU + (CHALAKIM_PER_MONTH * monthsElapsed); 530 } 531 532 /** 533 * Returns the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em> 534 * to the Jewish year and month that this Object is set to. 535 * 536 * @return the number of <em>chalakim</em> (parts - 1080 to the hour) from the original hypothetical <em>Molad Tohu</em> 537 */ 538 public long getChalakimSinceMoladTohu() { 539 return getChalakimSinceMoladTohu(jewishYear, jewishMonth); 540 } 541 542 /** 543 * Converts the {@link JewishDate#NISSAN} based constants used by this class to numeric month starting from 544 * {@link JewishDate#TISHREI}. This is required for <em>molad</em> calculations. 545 * 546 * @param year 547 * The Jewish year 548 * @param month 549 * The Jewish Month 550 * @return the Jewish month of the year starting with Tishrei 551 */ 552 private static int getJewishMonthOfYear(int year, int month) { 553 boolean isLeapYear = isJewishLeapYear(year); 554 return (month + (isLeapYear ? 6 : 5)) % (isLeapYear ? 13 : 12) + 1; 555 } 556 557 /** 558 * Validates the components of a Jewish date for validity. It will throw an {@link IllegalArgumentException} if the Jewish 559 * date is earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a {@link #isJewishLeapYear(int) 560 * leap year}), the day of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 or > 59 or 561 * <em>chalakim</em> < 0 or > 17. For larger a larger number of <em>chalakim</em> such as 793 (TaShTzaG) break the 562 * <em>chalakim</em> into minutes (18 <em>chalakim</em> per minutes, so it would be 44 minutes and 1 <em>chelek</em> in the 563 * case of 793 / <em>TaShTzaG</em>). 564 * 565 * @param year 566 * the Jewish year to validate. It will reject any year <= 3761 (lower than the year 1 Gregorian). 567 * @param month 568 * the Jewish month to validate. It will reject a month < 1 or > 12 (or 13 on a leap year) . 569 * @param dayOfMonth 570 * the day of the Jewish month to validate. It will reject any value < 1 or > 30 TODO: check calling 571 * methods to see if there is any reason that the class can validate that 30 is invalid for some months. 572 * @param hours 573 * the hours (for <em>molad</em> calculations). It will reject an hour < 0 or > 23 574 * @param minutes 575 * the minutes (for <em>molad</em> calculations). It will reject a minute < 0 or > 59 576 * @param chalakim 577 * the <em>chalakim</em> / parts (for <em>molad</em> calculations). It will reject a <em>chalakim</em> < 0 or > 578 * 17. For larger numbers such as 793 (<em>TaShTzaG</em>) break the <em>chalakim</em> into minutes (18 <em>chalakim</em> 579 * per minutes, so it would be 44 minutes and 1 <em>chelek</em> in the case of 793 / <em>TaShTzaG</em>) 580 * 581 * @throws IllegalArgumentException 582 * if a Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a leap year), 583 * the day of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 or > 59 or <em>chalakim</em> 584 * < 0 or > 17. For larger a larger number of <em>chalakim</em> such as 793 (<em>TaShTzaG</em>) break the 585 * <em>chalakim</em> into minutes (18 <em>chalakim</em> per minutes, so it would be 44 minutes and 1 <em>chelek</em> 586 * in the case of 793 (<em>TaShTzaG</em>). 587 */ 588 private static void validateJewishDate(int year, int month, int dayOfMonth, int hours, int minutes, int chalakim) { 589 if (month < NISSAN || month > getLastMonthOfJewishYear(year)) { 590 throw new IllegalArgumentException("The Jewish month has to be between 1 and 12 (or 13 on a leap year). " 591 + month + " is invalid for the year " + year + "."); 592 } 593 if (dayOfMonth < 1 || dayOfMonth > 30) { 594 throw new IllegalArgumentException("The Jewish day of month can't be < 1 or > 30. " + dayOfMonth 595 + " is invalid."); 596 } 597 // reject dates prior to 18 Teves, 3761 (1/1/1 AD). This restriction can be relaxed if the date coding is 598 // changed/corrected 599 if ((year < 3761) || (year == 3761 && (month >= TISHREI && month < TEVES)) 600 || (year == 3761 && month == TEVES && dayOfMonth < 18)) { 601 throw new IllegalArgumentException( 602 "A Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian) can't be set. " + year + ", " + month 603 + ", " + dayOfMonth + " is invalid."); 604 } 605 if (hours < 0 || hours > 23) { 606 throw new IllegalArgumentException("Hours < 0 or > 23 can't be set. " + hours + " is invalid."); 607 } 608 609 if (minutes < 0 || minutes > 59) { 610 throw new IllegalArgumentException("Minutes < 0 or > 59 can't be set. " + minutes + " is invalid."); 611 } 612 613 if (chalakim < 0 || chalakim > 17) { 614 throw new IllegalArgumentException( 615 "Chalakim/parts < 0 or > 17 can't be set. " 616 + chalakim 617 + " 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)"); 618 } 619 } 620 621 /** 622 * Validates the components of a Gregorian date for validity. It will throw an {@link IllegalArgumentException} if a 623 * year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in. 624 * 625 * @param year 626 * the Gregorian year to validate. It will reject any year < 1. 627 * @param month 628 * the Gregorian month number to validate. It will enforce that the month is between 0 - 11 like a 629 * {@link GregorianCalendar}, where {@link Calendar#JANUARY} has a value of 0. 630 * @param dayOfMonth 631 * the day of the Gregorian month to validate. It will reject any value < 1, but will allow values > 31 632 * since calling methods will simply set it to the maximum for that month. TODO: check calling methods to 633 * see if there is any reason that the class needs days > the maximum. 634 * @throws IllegalArgumentException 635 * if a year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in 636 * @see #validateGregorianYear(int) 637 * @see #validateGregorianMonth(int) 638 * @see #validateGregorianDayOfMonth(int) 639 */ 640 private static void validateGregorianDate(int year, int month, int dayOfMonth) { 641 validateGregorianMonth(month); 642 validateGregorianDayOfMonth(dayOfMonth); 643 validateGregorianYear(year); 644 } 645 646 /** 647 * Validates a Gregorian month for validity. 648 * 649 * @param month 650 * the Gregorian month number to validate. It will enforce that the month is between 0 - 11 like a 651 * {@link GregorianCalendar}, where {@link Calendar#JANUARY} has a value of 0. 652 */ 653 private static void validateGregorianMonth(int month) { 654 if (month > 11 || month < 0) { 655 throw new IllegalArgumentException("The Gregorian month has to be between 0 - 11. " + month 656 + " is invalid."); 657 } 658 } 659 660 /** 661 * Validates a Gregorian day of month for validity. 662 * 663 * @param dayOfMonth 664 * the day of the Gregorian month to validate. It will reject any value < 1, but will allow values > 31 665 * since calling methods will simply set it to the maximum for that month. TODO: check calling methods to 666 * see if there is any reason that the class needs days > the maximum. 667 */ 668 private static void validateGregorianDayOfMonth(int dayOfMonth) { 669 if (dayOfMonth <= 0) { 670 throw new IllegalArgumentException("The day of month can't be less than 1. " + dayOfMonth + " is invalid."); 671 } 672 } 673 674 /** 675 * Validates a Gregorian year for validity. 676 * 677 * @param year 678 * the Gregorian year to validate. It will reject any year < 1. 679 */ 680 private static void validateGregorianYear(int year) { 681 if (year < 1) { 682 throw new IllegalArgumentException("Years < 1 can't be calculated. " + year + " is invalid."); 683 } 684 } 685 686 /** 687 * Returns the number of days for a given Jewish year. ND+ER 688 * 689 * @param year 690 * the Jewish year 691 * @return the number of days for a given Jewish year. 692 * @see #isCheshvanLong() 693 * @see #isKislevShort() 694 */ 695 public static int getDaysInJewishYear(int year) { 696 return getJewishCalendarElapsedDays(year + 1) - getJewishCalendarElapsedDays(year); 697 } 698 699 /** 700 * Returns the number of days for the current year that the calendar is set to. 701 * 702 * @return the number of days for the Object's current Jewish year. 703 * @see #isCheshvanLong() 704 * @see #isKislevShort() 705 * @see #isJewishLeapYear() 706 */ 707 public int getDaysInJewishYear() { 708 return getDaysInJewishYear(getJewishYear()); 709 } 710 711 /** 712 * Returns if Cheshvan is long in a given Jewish year. The method name isLong is done since in a Kesidran (ordered) 713 * year Cheshvan is short. ND+ER 714 * 715 * @param year 716 * the year 717 * @return true if Cheshvan is long in Jewish year. 718 * @see #isCheshvanLong() 719 * @see #getCheshvanKislevKviah() 720 */ 721 private static boolean isCheshvanLong(int year) { 722 return getDaysInJewishYear(year) % 10 == 5; 723 } 724 725 /** 726 * Returns if Cheshvan is long (30 days VS 29 days) for the current year that the calendar is set to. The method 727 * name isLong is done since in a Kesidran (ordered) year Cheshvan is short. 728 * 729 * @return true if Cheshvan is long for the current year that the calendar is set to 730 * @see #isCheshvanLong() 731 */ 732 public boolean isCheshvanLong() { 733 return isCheshvanLong(getJewishYear()); 734 } 735 736 /** 737 * Returns if Kislev is short (29 days VS 30 days) in a given Jewish year. The method name isShort is done since in 738 * a Kesidran (ordered) year Kislev is long. ND+ER 739 * 740 * @param year 741 * the Jewish year 742 * @return true if Kislev is short for the given Jewish year. 743 * @see #isKislevShort() 744 * @see #getCheshvanKislevKviah() 745 */ 746 private static boolean isKislevShort(int year) { 747 return getDaysInJewishYear(year) % 10 == 3; 748 } 749 750 /** 751 * Returns if the Kislev is short for the year that this class is set to. The method name isShort is done since in a 752 * Kesidran (ordered) year Kislev is long. 753 * 754 * @return true if Kislev is short for the year that this class is set to 755 */ 756 public boolean isKislevShort() { 757 return isKislevShort(getJewishYear()); 758 } 759 760 /** 761 * Returns the Cheshvan and Kislev kviah (whether a Jewish year is short, regular or long). It will return 762 * {@link #SHELAIMIM} if both cheshvan and kislev are 30 days, {@link #KESIDRAN} if Cheshvan is 29 days and Kislev 763 * is 30 days and {@link #CHASERIM} if both are 29 days. 764 * 765 * @return {@link #SHELAIMIM} if both cheshvan and kislev are 30 days, {@link #KESIDRAN} if Cheshvan is 29 days and 766 * Kislev is 30 days and {@link #CHASERIM} if both are 29 days. 767 * @see #isCheshvanLong() 768 * @see #isKislevShort() 769 */ 770 public int getCheshvanKislevKviah() { 771 if (isCheshvanLong() && !isKislevShort()) { 772 return SHELAIMIM; 773 } else if (!isCheshvanLong() && isKislevShort()) { 774 return CHASERIM; 775 } else { 776 return KESIDRAN; 777 } 778 } 779 780 /** 781 * Returns the number of days of a Jewish month for a given month and year. 782 * 783 * @param month 784 * the Jewish month 785 * @param year 786 * the Jewish Year 787 * @return the number of days for a given Jewish month 788 */ 789 private static int getDaysInJewishMonth(int month, int year) { 790 if ((month == IYAR) || (month == TAMMUZ) || (month == ELUL) || ((month == CHESHVAN) && !(isCheshvanLong(year))) 791 || ((month == KISLEV) && isKislevShort(year)) || (month == TEVES) 792 || ((month == ADAR) && !(isJewishLeapYear(year))) || (month == ADAR_II)) { 793 return 29; 794 } else { 795 return 30; 796 } 797 } 798 799 /** 800 * Returns the number of days of the Jewish month that the calendar is currently set to. 801 * 802 * @return the number of days for the Jewish month that the calendar is currently set to. 803 */ 804 public int getDaysInJewishMonth() { 805 return getDaysInJewishMonth(getJewishMonth(), getJewishYear()); 806 } 807 808 /** 809 * Computes the Jewish date from the absolute date. 810 */ 811 private void absDateToJewishDate() { 812 // Approximation from below 813 jewishYear = (gregorianAbsDate - JEWISH_EPOCH) / 366; 814 // Search forward for year from the approximation 815 while (gregorianAbsDate >= jewishDateToAbsDate(jewishYear + 1, TISHREI, 1)) { 816 jewishYear++; 817 } 818 // Search forward for month from either Tishri or Nissan. 819 if (gregorianAbsDate < jewishDateToAbsDate(jewishYear, NISSAN, 1)) { 820 jewishMonth = TISHREI;// Start at Tishri 821 } else { 822 jewishMonth = NISSAN;// Start at Nissan 823 } 824 while (gregorianAbsDate > jewishDateToAbsDate(jewishYear, jewishMonth, getDaysInJewishMonth())) { 825 jewishMonth++; 826 } 827 // Calculate the day by subtraction 828 jewishDay = gregorianAbsDate - jewishDateToAbsDate(jewishYear, jewishMonth, 1) + 1; 829 } 830 831 /** 832 * Returns the absolute date of Jewish date. ND+ER 833 * 834 * @param year 835 * the Jewish year. The year can't be negative 836 * @param month 837 * the Jewish month starting with Nissan. Nissan expects a value of 1 etc. until Adar with a value of 12. 838 * For a leap year, 13 will be the expected value for Adar II. Use the constants {@link JewishDate#NISSAN} 839 * etc. 840 * @param dayOfMonth 841 * the Jewish day of month. valid values are 1-30. If the day of month is set to 30 for a month that only 842 * has 29 days, the day will be set as 29. 843 * @return the absolute date of the Jewish date. 844 */ 845 private static int jewishDateToAbsDate(int year, int month, int dayOfMonth) { 846 int elapsed = getDaysSinceStartOfJewishYear(year, month, dayOfMonth); 847 // add elapsed days this year + Days in prior years + Days elapsed before absolute year 1 848 return elapsed + getJewishCalendarElapsedDays(year) + JEWISH_EPOCH; 849 } 850 851 /** 852 * 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> 853 * with the {@link #getMoladHours() hours}, {@link #getMoladMinutes() minutes} and {@link #getMoladChalakim() 854 * chalakim} set. In the current implementation, it sets the <em>molad</em> time based on a midnight date rollover. This 855 * 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, 856 * 2011 12:00 AM and 7 chalakim, will have the following values: hours: 0, minutes: 0, Chalakim: 7. 857 * 858 * @return a JewishDate {@link Object} set to the date of the <em>molad</em> with the {@link #getMoladHours() hours}, 859 * {@link #getMoladMinutes() minutes} and {@link #getMoladChalakim() <em>chalakim</em>} set. 860 */ 861 public JewishDate getMolad() { 862 JewishDate moladDate = new JewishDate(getChalakimSinceMoladTohu()); 863 if (moladDate.getMoladHours() >= 6) { 864 moladDate.forward(Calendar.DATE, 1); 865 } 866 moladDate.setMoladHours((moladDate.getMoladHours() + 18) % 24); 867 return moladDate; 868 } 869 870 /** 871 * Returns the number of days from the Jewish epoch from the number of <em>chalakim</em> from the epoch passed in. 872 * 873 * @param chalakim 874 * the number of <em>chalakim</em> since the beginning of Sunday prior to BaHaRaD 875 * @return the number of days from the Jewish epoch 876 */ 877 private static int moladToAbsDate(long chalakim) { 878 return (int) (chalakim / CHALAKIM_PER_DAY) + JEWISH_EPOCH; 879 } 880 881 /** 882 * Constructor that creates a JewishDate based on a <em>molad</em> passed in. The <em>molad</em> would be the number of 883 * <em>chalakim</em> / parts starting at the beginning of Sunday prior to the <em>Molad Tohu BeHaRaD</em> (<em>Be</em> = 884 * Monday, <em>Ha</em> = 5 hours and <em>RaD</em> = 204 <em>chalakim</em> / parts) - prior to the start of the Jewish 885 * calendar. <em>BeHaRaD</em> is 23:11:20 on Sunday night(5 hours 204/1080 <em>chalakim</em> after sunset on Sunday evening). 886 * 887 * @param molad the number of <em>chalakim</em> since the beginning of Sunday prior to BaHaRaD 888 */ 889 public JewishDate(long molad) { 890 absDateToDate(moladToAbsDate(molad)); 891 int conjunctionDay = (int) (molad / (long) CHALAKIM_PER_DAY); 892 int conjunctionParts = (int) (molad - conjunctionDay * (long) CHALAKIM_PER_DAY); 893 setMoladTime(conjunctionParts); 894 } 895 896 /** 897 * Sets the <em>molad</em> time (hours minutes and chalakim) based on the number of <em>chalakim</em> since the start of the day. 898 * 899 * @param chalakim 900 * the number of <em>chalakim</em> since the start of the day. 901 */ 902 private void setMoladTime(int chalakim) { 903 int adjustedChalakim = chalakim; 904 setMoladHours(adjustedChalakim / CHALAKIM_PER_HOUR); 905 adjustedChalakim = adjustedChalakim - (getMoladHours() * CHALAKIM_PER_HOUR); 906 setMoladMinutes(adjustedChalakim / CHALAKIM_PER_MINUTE); 907 setMoladChalakim(adjustedChalakim - moladMinutes * CHALAKIM_PER_MINUTE); 908 } 909 910 /** 911 * returns the number of days from Rosh Hashana of the date passed in, to the full date passed in. 912 * 913 * @param year 914 * the Jewish year 915 * @param month 916 * the Jewish month 917 * @param dayOfMonth 918 * the day in the Jewish month 919 * @return the number of days 920 */ 921 private static int getDaysSinceStartOfJewishYear(int year, int month, int dayOfMonth) { 922 int elapsedDays = dayOfMonth; 923 // Before Tishrei (from Nissan to Tishrei), add days in prior months 924 if (month < TISHREI) { 925 // this year before and after Nissan. 926 for (int m = TISHREI; m <= getLastMonthOfJewishYear(year); m++) { 927 elapsedDays += getDaysInJewishMonth(m, year); 928 } 929 for (int m = NISSAN; m < month; m++) { 930 elapsedDays += getDaysInJewishMonth(m, year); 931 } 932 } else { // Add days in prior months this year 933 for (int m = TISHREI; m < month; m++) { 934 elapsedDays += getDaysInJewishMonth(m, year); 935 } 936 } 937 return elapsedDays; 938 } 939 940 /** 941 * returns the number of days from Rosh Hashana of the date passed in, to the full date passed in. 942 * 943 * @return the number of days 944 */ 945 public int getDaysSinceStartOfJewishYear() { 946 return getDaysSinceStartOfJewishYear(getJewishYear(), getJewishMonth(), getJewishDayOfMonth()); 947 } 948 949 /** 950 * Creates a Jewish date based on a Jewish year, month and day of month. 951 * 952 * @param jewishYear 953 * the Jewish year 954 * @param jewishMonth 955 * the Jewish month. The method expects a 1 for Nissan ... 12 for Adar and 13 for Adar II. Use the 956 * constants {@link #NISSAN} ... {@link #ADAR} (or {@link #ADAR_II} for a leap year Adar II) to avoid any 957 * confusion. 958 * @param jewishDayOfMonth 959 * the Jewish day of month. If 30 is passed in for a month with only 29 days (for example {@link #IYAR}, 960 * or {@link #KISLEV} in a year that {@link #isKislevShort()}), the 29th (last valid date of the month) 961 * will be set 962 * @throws IllegalArgumentException 963 * if the day of month is < 1 or > 30, or a year of < 0 is passed in. 964 */ 965 public JewishDate(int jewishYear, int jewishMonth, int jewishDayOfMonth) { 966 setJewishDate(jewishYear, jewishMonth, jewishDayOfMonth); 967 } 968 969 /** 970 * Default constructor will set a default date to the current system date. 971 */ 972 public JewishDate() { 973 resetDate(); 974 } 975 976 /** 977 * A constructor that initializes the date to the {@link java.util.Date Date} parameter. 978 * 979 * @param date 980 * the <code>Date</code> to set the calendar to 981 * @throws IllegalArgumentException 982 * if the date would fall prior to the January 1, 1 AD 983 */ 984 public JewishDate(Date date) { 985 setDate(date); 986 } 987 988 /** 989 * A constructor that initializes the date to the {@link java.util.Calendar Calendar} parameter. 990 * 991 * @param calendar 992 * the <code>Calendar</code> to set the calendar to 993 * @throws IllegalArgumentException 994 * if the {@link Calendar#ERA} is {@link GregorianCalendar#BC} 995 */ 996 public JewishDate(Calendar calendar) { 997 setDate(calendar); 998 } 999 1000 /** 1001 * A constructor that initializes the date to the {@link java.time.LocalDate LocalDate} parameter. 1002 * 1003 * @param localDate 1004 * the <code>LocalDate</code> to set the calendar to 1005 * @throws IllegalArgumentException 1006 * if the {@link Calendar#ERA} is {@link GregorianCalendar#BC} 1007 */ 1008 public JewishDate(LocalDate localDate) { 1009 setDate(localDate); 1010 } 1011 1012 /** 1013 * Sets the date based on a {@link java.util.Calendar Calendar} object. Modifies the Jewish date as well. 1014 * 1015 * @param calendar 1016 * the <code>Calendar</code> to set the calendar to 1017 * @throws IllegalArgumentException 1018 * if the {@link Calendar#ERA} is {@link GregorianCalendar#BC} 1019 */ 1020 public void setDate(Calendar calendar) { 1021 if (calendar.get(Calendar.ERA) == GregorianCalendar.BC) { 1022 throw new IllegalArgumentException("Calendars with a BC era are not supported. The year " 1023 + calendar.get(Calendar.YEAR) + " BC is invalid."); 1024 } 1025 gregorianMonth = calendar.get(Calendar.MONTH) + 1; 1026 gregorianDayOfMonth = calendar.get(Calendar.DATE); 1027 gregorianYear = calendar.get(Calendar.YEAR); 1028 gregorianAbsDate = gregorianDateToAbsDate(gregorianYear, gregorianMonth, gregorianDayOfMonth); // init the date 1029 absDateToJewishDate(); 1030 1031 dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1; // set day of week 1032 } 1033 1034 /** 1035 * Sets the date based on a {@link java.util.Date Date} object. Modifies the Jewish date as well. 1036 * 1037 * @param date 1038 * the <code>Date</code> to set the calendar to 1039 * @throws IllegalArgumentException 1040 * if the date would fall prior to the year 1 AD 1041 */ 1042 public void setDate(Date date) { 1043 Calendar cal = Calendar.getInstance(); 1044 cal.setTime(date); 1045 setDate(cal); 1046 } 1047 1048 /** 1049 * Sets the date based on a {@link java.time.LocalDate LocalDate} object. Modifies the Jewish date as well. 1050 * 1051 * @param localDate 1052 * the <code>LocalDate</code> to set the calendar to 1053 * @throws IllegalArgumentException 1054 * if the date would fall prior to the year 1 AD 1055 */ 1056 public void setDate(LocalDate localDate) { 1057 Calendar cal = Calendar.getInstance(); 1058 cal.set(localDate.getYear(), localDate.getMonthValue() - 1, localDate.getDayOfMonth()); 1059 setDate(cal); 1060 } 1061 1062 /** 1063 * Sets the Gregorian Date, and updates the Jewish date accordingly. Like the Java Calendar A value of 0 is expected 1064 * for January. 1065 * 1066 * @param year 1067 * the Gregorian year 1068 * @param month 1069 * the Gregorian month. Like the Java Calendar, this class expects 0 for January 1070 * @param dayOfMonth 1071 * the Gregorian day of month. If this is > the number of days in the month/year, the last valid date of 1072 * the month will be set 1073 * @throws IllegalArgumentException 1074 * if a year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in 1075 */ 1076 public void setGregorianDate(int year, int month, int dayOfMonth) { 1077 validateGregorianDate(year, month, dayOfMonth); 1078 setInternalGregorianDate(year, month + 1, dayOfMonth); 1079 } 1080 1081 /** 1082 * Sets the hidden internal representation of the Gregorian date , and updates the Jewish date accordingly. While 1083 * public getters and setters have 0 based months matching the Java Calendar classes, This class internally 1084 * represents the Gregorian month starting at 1. When this is called it will not adjust the month to match the Java 1085 * Calendar classes. 1086 * 1087 * @param year the year 1088 * @param month the month 1089 * @param dayOfMonth the day of month 1090 */ 1091 private void setInternalGregorianDate(int year, int month, int dayOfMonth) { 1092 // make sure date is a valid date for the given month, if not, set to last day of month 1093 if (dayOfMonth > getLastDayOfGregorianMonth(month, year)) { 1094 dayOfMonth = getLastDayOfGregorianMonth(month, year); 1095 } 1096 // init month, date, year 1097 gregorianMonth = month; 1098 gregorianDayOfMonth = dayOfMonth; 1099 gregorianYear = year; 1100 1101 gregorianAbsDate = gregorianDateToAbsDate(gregorianYear, gregorianMonth, gregorianDayOfMonth); // init date 1102 absDateToJewishDate(); 1103 1104 dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1; // set day of week 1105 } 1106 1107 /** 1108 * Sets the Jewish Date and updates the Gregorian date accordingly. 1109 * 1110 * @param year 1111 * the Jewish year. The year can't be negative 1112 * @param month 1113 * the Jewish month starting with Nissan. A value of 1 is expected for Nissan ... 12 for Adar and 13 for 1114 * Adar II. Use the constants {@link #NISSAN} ... {@link #ADAR} (or {@link #ADAR_II} for a leap year Adar 1115 * II) to avoid any confusion. 1116 * @param dayOfMonth 1117 * the Jewish day of month. valid values are 1-30. If the day of month is set to 30 for a month that only 1118 * has 29 days, the day will be set as 29. 1119 * @throws IllegalArgumentException 1120 * if a Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a 1121 * leap year) or the day of month is < 1 or > 30 is passed in 1122 */ 1123 public void setJewishDate(int year, int month, int dayOfMonth) { 1124 setJewishDate(year, month, dayOfMonth, 0, 0, 0); 1125 } 1126 1127 /** 1128 * Sets the Jewish Date and updates the Gregorian date accordingly. 1129 * 1130 * @param year 1131 * the Jewish year. The year can't be negative 1132 * @param month 1133 * the Jewish month starting with Nissan. A value of 1 is expected for Nissan ... 12 for Adar and 13 for 1134 * Adar II. Use the constants {@link #NISSAN} ... {@link #ADAR} (or {@link #ADAR_II} for a leap year Adar 1135 * II) to avoid any confusion. 1136 * @param dayOfMonth 1137 * the Jewish day of month. valid values are 1-30. If the day of month is set to 30 for a month that only 1138 * has 29 days, the day will be set as 29. 1139 * 1140 * @param hours 1141 * the hour of the day. Used for <em>molad</em> calculations 1142 * @param minutes 1143 * the minutes. Used for <em>molad</em> calculations 1144 * @param chalakim 1145 * the <em>chalakim</em> / parts. Used for <em>molad</em> calculations. The <em>chalakim</em> should not 1146 * exceed 17. Minutes should be used for larger numbers. 1147 * 1148 * @throws IllegalArgumentException 1149 * 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 1150 * of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 > 59 or <em>chalakim</em> < 0 > 17. For 1151 * larger a larger number of <em>chalakim</em> such as 793 (<em>TaShTzaG</em>) break the <em>chalakim</em> into minutes (18 1152 * <em>chalakim</em> per minutes, so it would be 44 minutes and 1 <em>chelek</em> in the case of 793 (<em>TaShTzaG</em>). 1153 */ 1154 public void setJewishDate(int year, int month, int dayOfMonth, int hours, int minutes, int chalakim) { 1155 validateJewishDate(year, month, dayOfMonth, hours, minutes, chalakim); 1156 1157 // if 30 is passed for a month that only has 29 days (for example by rolling the month from a month that had 30 1158 // days to a month that only has 29) set the date to 29th 1159 if (dayOfMonth > getDaysInJewishMonth(month, year)) { 1160 dayOfMonth = getDaysInJewishMonth(month, year); 1161 } 1162 1163 jewishMonth = month; 1164 jewishDay = dayOfMonth; 1165 jewishYear = year; 1166 moladHours = hours; 1167 moladMinutes = minutes; 1168 moladChalakim = chalakim; 1169 1170 gregorianAbsDate = jewishDateToAbsDate(jewishYear, jewishMonth, jewishDay); // reset Gregorian date 1171 absDateToDate(gregorianAbsDate); 1172 1173 dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1; // reset day of week 1174 } 1175 1176 /** 1177 * Returns this object's date as a {@link java.util.Calendar} object. 1178 * 1179 * @return The {@link java.util.Calendar} 1180 */ 1181 public Calendar getGregorianCalendar() { 1182 Calendar calendar = Calendar.getInstance(); 1183 calendar.set(getGregorianYear(), getGregorianMonth(), getGregorianDayOfMonth()); 1184 return calendar; 1185 } 1186 1187 /** 1188 * Returns this object's date as a {@link java.time.LocalDate} object. 1189 * 1190 * @return The {@link java.time.LocalDate} 1191 */ 1192 public LocalDate getLocalDate() { 1193 return LocalDate.of(getGregorianYear(), getGregorianMonth() + 1, getGregorianDayOfMonth()); 1194 } 1195 1196 /** 1197 * Resets this date to the current system date. 1198 */ 1199 public void resetDate() { 1200 Calendar calendar = Calendar.getInstance(); 1201 setDate(calendar); 1202 } 1203 1204 /** 1205 * Returns a string containing the Jewish date in the form, "day Month, year" e.g. "21 Shevat, 5729". For more 1206 * complex formatting, use the formatter classes. 1207 * 1208 * @return the Jewish date in the form "day Month, year" e.g. "21 Shevat, 5729" 1209 * @see HebrewDateFormatter#format(JewishDate) 1210 */ 1211 public String toString() { 1212 return new HebrewDateFormatter().format(this); 1213 } 1214 1215 /** 1216 * Rolls the date, month or year forward by the amount passed in. It modifies both the Gregorian and Jewish dates accordingly. 1217 * If manipulation beyond the fields supported here is required, use the {@link Calendar} class {@link Calendar#add(int, int)} 1218 * or {@link Calendar#roll(int, int)} methods in the following manner. 1219 * 1220 * <pre> 1221 * <code> 1222 * Calendar cal = jewishDate.getTime(); // get a java.util.Calendar representation of the JewishDate 1223 * cal.add(Calendar.MONTH, 3); // add 3 Gregorian months 1224 * jewishDate.setDate(cal); // set the updated calendar back to this class 1225 * </code> 1226 * </pre> 1227 * 1228 * @param field the calendar field to be forwarded. The must be {@link Calendar#DATE}, {@link Calendar#MONTH} or {@link Calendar#YEAR} 1229 * @param amount the positive amount to move forward 1230 * @throws IllegalArgumentException if the field is anything besides {@link Calendar#DATE}, {@link Calendar#MONTH} or {@link Calendar#YEAR} 1231 * or if the amount is less than 1 1232 * 1233 * @see #back() 1234 * @see Calendar#add(int, int) 1235 * @see Calendar#roll(int, int) 1236 */ 1237 public void forward(int field, int amount) { 1238 if (field != Calendar.DATE && field != Calendar.MONTH && field != Calendar.YEAR) { 1239 throw new IllegalArgumentException("Unsupported field was passed to Forward. Only Calendar.DATE, Calendar.MONTH or Calendar.YEAR are supported."); 1240 } 1241 if (amount < 1) { 1242 throw new IllegalArgumentException("JewishDate.forward() does not support amounts less than 1. See JewishDate.back()"); 1243 } 1244 if (field == Calendar.DATE) { 1245 // Change Gregorian date 1246 for (int i = 0; i < amount; i++) { 1247 if (gregorianDayOfMonth == getLastDayOfGregorianMonth(gregorianMonth, gregorianYear)) { 1248 gregorianDayOfMonth = 1; 1249 // if last day of year 1250 if (gregorianMonth == 12) { 1251 gregorianYear++; 1252 gregorianMonth = 1; 1253 } else { 1254 gregorianMonth++; 1255 } 1256 } else { // if not last day of month 1257 gregorianDayOfMonth++; 1258 } 1259 1260 // Change the Jewish Date 1261 if (jewishDay == getDaysInJewishMonth()) { 1262 // if it last day of elul (i.e. last day of Jewish year) 1263 if (jewishMonth == ELUL) { 1264 jewishYear++; 1265 jewishMonth++; 1266 jewishDay = 1; 1267 } else if (jewishMonth == getLastMonthOfJewishYear(jewishYear)) { 1268 // if it is the last day of Adar, or Adar II as case may be 1269 jewishMonth = NISSAN; 1270 jewishDay = 1; 1271 } else { 1272 jewishMonth++; 1273 jewishDay = 1; 1274 } 1275 } else { // if not last date of month 1276 jewishDay++; 1277 } 1278 1279 if (dayOfWeek == 7) { // if last day of week, loop back to Sunday 1280 dayOfWeek = 1; 1281 } else { 1282 dayOfWeek++; 1283 } 1284 1285 gregorianAbsDate++; // increment the absolute date 1286 } 1287 } else if (field == Calendar.MONTH) { 1288 forwardJewishMonth(amount); 1289 } else { 1290 setJewishYear(getJewishYear() + amount); 1291 } 1292 } 1293 1294 /** 1295 * Forward the Jewish date by the number of months passed in. 1296 * FIXME: Deal with forwarding a date such as 30 Nissan by a month. 30 Iyar does not exist. This should be dealt with similar to 1297 * the way that the Java Calendar behaves (not that simple since there is a difference between add() or roll(). 1298 * 1299 * @throws IllegalArgumentException if the amount is less than 1 1300 * @param amount the number of months to roll the month forward 1301 */ 1302 private void forwardJewishMonth(int amount) { 1303 if (amount < 1) { 1304 throw new IllegalArgumentException("the amount of months to forward has to be greater than zero."); 1305 } 1306 for (int i = 0; i < amount; i++) { 1307 if (getJewishMonth() == ELUL) { 1308 setJewishMonth(TISHREI); 1309 setJewishYear(getJewishYear() + 1); 1310 } else if ((! isJewishLeapYear() && getJewishMonth() == ADAR) 1311 || (isJewishLeapYear() && getJewishMonth() == ADAR_II)){ 1312 setJewishMonth(NISSAN); 1313 } else { 1314 setJewishMonth(getJewishMonth() + 1); 1315 } 1316 } 1317 } 1318 1319 /** 1320 * Rolls the date back by 1 day. It modifies both the Gregorian and Jewish dates accordingly. The API does not 1321 * currently offer the ability to forward more than one day at a time, or to forward by month or year. If such 1322 * manipulation is required use the {@link Calendar} class {@link Calendar#add(int, int)} or 1323 * {@link Calendar#roll(int, int)} methods in the following manner. 1324 * 1325 * <pre> 1326 * <code> 1327 * Calendar cal = jewishDate.getTime(); // get a java.util.Calendar representation of the JewishDate 1328 * cal.add(Calendar.MONTH, -3); // subtract 3 Gregorian months 1329 * jewishDate.setDate(cal); // set the updated calendar back to this class 1330 * </code> 1331 * </pre> 1332 * 1333 * @see #back() 1334 * @see Calendar#add(int, int) 1335 * @see Calendar#roll(int, int) 1336 */ 1337 public void back() { 1338 // Change Gregorian date 1339 if (gregorianDayOfMonth == 1) { // if first day of month 1340 if (gregorianMonth == 1) { // if first day of year 1341 gregorianMonth = 12; 1342 gregorianYear--; 1343 } else { 1344 gregorianMonth--; 1345 } 1346 // change to last day of previous month 1347 gregorianDayOfMonth = getLastDayOfGregorianMonth(gregorianMonth, gregorianYear); 1348 } else { 1349 gregorianDayOfMonth--; 1350 } 1351 // change Jewish date 1352 if (jewishDay == 1) { // if first day of the Jewish month 1353 if (jewishMonth == NISSAN) { 1354 jewishMonth = getLastMonthOfJewishYear(jewishYear); 1355 } else if (jewishMonth == TISHREI) { // if Rosh Hashana 1356 jewishYear--; 1357 jewishMonth--; 1358 } else { 1359 jewishMonth--; 1360 } 1361 jewishDay = getDaysInJewishMonth(); 1362 } else { 1363 jewishDay--; 1364 } 1365 1366 if (dayOfWeek == 1) { // if first day of week, loop back to Saturday 1367 dayOfWeek = 7; 1368 } else { 1369 dayOfWeek--; 1370 } 1371 gregorianAbsDate--; // change the absolute date 1372 } 1373 1374 /** 1375 * Indicates whether some other object is "equal to" this one. 1376 * @see Object#equals(Object) 1377 */ 1378 public boolean equals(Object object) { 1379 if (this == object) { 1380 return true; 1381 } 1382 if (!(object instanceof JewishDate)) { 1383 return false; 1384 } 1385 JewishDate jewishDate = (JewishDate) object; 1386 return gregorianAbsDate == jewishDate.getAbsDate(); 1387 } 1388 1389 /** 1390 * Compares two dates as per the compareTo() method in the Comparable interface. Returns a value less than 0 if this 1391 * date is "less than" (before) the date, greater than 0 if this date is "greater than" (after) the date, or 0 if 1392 * they are equal. 1393 */ 1394 public int compareTo(JewishDate jewishDate) { 1395 return Integer.compare(gregorianAbsDate, jewishDate.getAbsDate()); 1396 } 1397 1398 /** 1399 * Returns the Gregorian month (between 0-11). 1400 * 1401 * @return the Gregorian month (between 0-11). Like the java.util.Calendar, months are 0 based. 1402 */ 1403 public int getGregorianMonth() { 1404 return gregorianMonth - 1; 1405 } 1406 1407 /** 1408 * Returns the Gregorian day of the month. 1409 * 1410 * @return the Gregorian day of the mont 1411 */ 1412 public int getGregorianDayOfMonth() { 1413 return gregorianDayOfMonth; 1414 } 1415 1416 /** 1417 * Returns the Gregorian year. 1418 * 1419 * @return the Gregorian year 1420 */ 1421 public int getGregorianYear() { 1422 return gregorianYear; 1423 } 1424 1425 /** 1426 * Returns the Jewish month 1-12 (or 13 years in a leap year). The month count starts with 1 for Nissan and goes to 1427 * 13 for Adar II 1428 * 1429 * @return the Jewish month from 1 to 12 (or 13 years in a leap year). The month count starts with 1 for Nissan and 1430 * goes to 13 for Adar II 1431 */ 1432 public int getJewishMonth() { 1433 return jewishMonth; 1434 } 1435 1436 /** 1437 * Returns the Jewish day of month. 1438 * 1439 * @return the Jewish day of the month 1440 */ 1441 public int getJewishDayOfMonth() { 1442 return jewishDay; 1443 } 1444 1445 /** 1446 * Returns the Jewish year. 1447 * 1448 * @return the Jewish year 1449 */ 1450 public int getJewishYear() { 1451 return jewishYear; 1452 } 1453 1454 /** 1455 * Returns the day of the week as a number between 1-7. 1456 * 1457 * @return the day of the week as a number between 1-7. 1458 */ 1459 public int getDayOfWeek() { 1460 return dayOfWeek; 1461 } 1462 1463 /** 1464 * Sets the Gregorian month. 1465 * 1466 * @param month 1467 * the Gregorian month 1468 * 1469 * @throws IllegalArgumentException 1470 * if a month < 0 or > 11 is passed in 1471 */ 1472 public void setGregorianMonth(int month) { 1473 validateGregorianMonth(month); 1474 setInternalGregorianDate(gregorianYear, month + 1, gregorianDayOfMonth); 1475 } 1476 1477 /** 1478 * sets the Gregorian year. 1479 * 1480 * @param year 1481 * the Gregorian year. 1482 * @throws IllegalArgumentException 1483 * if a year of < 1 is passed in 1484 */ 1485 public void setGregorianYear(int year) { 1486 validateGregorianYear(year); 1487 setInternalGregorianDate(year, gregorianMonth, gregorianDayOfMonth); 1488 } 1489 1490 /** 1491 * sets the Gregorian Day of month. 1492 * 1493 * @param dayOfMonth 1494 * the Gregorian Day of month. 1495 * @throws IllegalArgumentException 1496 * if the day of month of < 1 is passed in 1497 */ 1498 public void setGregorianDayOfMonth(int dayOfMonth) { 1499 validateGregorianDayOfMonth(dayOfMonth); 1500 setInternalGregorianDate(gregorianYear, gregorianMonth, dayOfMonth); 1501 } 1502 1503 /** 1504 * sets the Jewish month. 1505 * 1506 * @param month 1507 * the Jewish month from 1 to 12 (or 13 years in a leap year). The month count starts with 1 for Nissan 1508 * and goes to 13 for Adar II 1509 * @throws IllegalArgumentException 1510 * if a month < 1 or > 12 (or 13 on a leap year) is passed in 1511 */ 1512 public void setJewishMonth(int month) { 1513 setJewishDate(jewishYear, month, jewishDay); 1514 } 1515 1516 /** 1517 * sets the Jewish year. 1518 * 1519 * @param year 1520 * the Jewish year 1521 * @throws IllegalArgumentException 1522 * if a year of < 3761 is passed in. The same will happen if the year is 3761 and the month and day 1523 * previously set are < 18 Teves (prior to Jan 1, 1 AD) 1524 */ 1525 public void setJewishYear(int year) { 1526 setJewishDate(year, jewishMonth, jewishDay); 1527 } 1528 1529 /** 1530 * sets the Jewish day of month. 1531 * 1532 * @param dayOfMonth 1533 * the Jewish day of month 1534 * @throws IllegalArgumentException 1535 * if the day of month is < 1 or > 30 is passed in 1536 */ 1537 public void setJewishDayOfMonth(int dayOfMonth) { 1538 setJewishDate(jewishYear, jewishMonth, dayOfMonth); 1539 } 1540 1541 /** 1542 * A method that creates a <a href="http://en.wikipedia.org/wiki/Object_copy#Deep_copy">deep copy</a> of the object. 1543 * 1544 * @see Object#clone() 1545 */ 1546 public Object clone() { 1547 JewishDate clone = null; 1548 try { 1549 clone = (JewishDate) super.clone(); 1550 } catch (CloneNotSupportedException cnse) { 1551 // Required by the compiler. Should never be reached since we implement clone() 1552 } 1553 if (clone != null) { 1554 clone.setInternalGregorianDate(gregorianYear, gregorianMonth, gregorianDayOfMonth); 1555 } 1556 return clone; 1557 } 1558 1559 /** 1560 * Overrides {@link Object#hashCode()}. 1561 * @see Object#hashCode() 1562 */ 1563 public int hashCode() { 1564 int result = 17; 1565 result = 37 * result + getClass().hashCode(); // needed or this and subclasses will return identical hash 1566 result += 37 * result + gregorianAbsDate; 1567 return result; 1568 } 1569}