001/* 002 * Zmanim Java API 003 * Copyright (C) 2011 - 2021 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 - 2021 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 Gregorian 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 molad BaHaRaD. Calculated as 1 day, 5 hours and 204 chalakim = (24 + 5) * 162 * 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</em> <em>chalakim</em>.*/ 201 private int moladChalakim; 202 203 /** 204 * Returns the molad 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 molad 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 molad hours. 219 * 220 * @param moladHours 221 * the molad 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 molad 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 molad 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 molad minutes. The expectation is that the traditional minute-less chalakim will be broken out to 247 * minutes and {@link #setMoladChalakim(int) chalakim/parts} , so 793 (TaShTZaG) parts would have the minutes set to 248 * 44 and chalakim 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 molad chalakim/parts. The expectation is that the traditional minute-less chalakim will be broken out to 264 * {@link #setMoladMinutes(int) minutes} and chalakim, so 793 (TaShTZaG) parts would have the minutes set to 44 and 265 * chalakim to 1. 266 * 267 * @param moladChalakim 268 * the molad chalakim/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 molad chalakim/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 molad chalakim/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 the 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 on 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 on 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 molad Tohu BaHaRaD (Be = Monday, Ha= 5 hours and Rad =204 457 * chalakim/parts) prior to the start of the Jewish calendar, to the mean conjunction of Tishri of the 458 * Jewish year. BeHaRaD is 23:11:20 on Sunday night(5 hours 204/1080 chalakim after sunset on Sunday 459 * 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 // private static int getJewishCalendarElapsedDaysOLD(int year) { 470 // // Jewish lunar month = 29 days, 12 hours and 793 chalakim 471 // // Molad Tohu = BeHaRaD - Monday, 5 hours (11 PM) and 204 chalakim 472 // final int chalakimTashTZag = 793; // chalakim in a lunar month 473 // final int chalakimTohuRaD = 204; // chalakim from original molad Tohu BeHaRaD 474 // final int hoursTohuHa = 5; // hours from original molad Tohu BeHaRaD 475 // final int dayTohu = 1; // Monday (0 based) 476 // 477 // int monthsElapsed = (235 * ((year - 1) / 19)) // Months in complete 19 year lunar (Metonic) cycles so far 478 // + (12 * ((year - 1) % 19)) // Regular months in this cycle 479 // + ((7 * ((year - 1) % 19) + 1) / 19); // Leap months this cycle 480 // // start with Molad Tohu BeHaRaD 481 // // start with RaD of BeHaRaD and add TaShTzaG (793) chalakim plus elapsed chalakim 482 // int partsElapsed = chalakimTohuRaD + chalakimTashTZag * (monthsElapsed % 1080); 483 // // start with Ha hours of BeHaRaD, add 12 hour remainder of lunar month add hours elapsed 484 // int hoursElapsed = hoursTohuHa + 12 * monthsElapsed + 793 * (monthsElapsed / 1080) + partsElapsed / 1080; 485 // // start with Monday of BeHaRaD = 1 (0 based), add 29 days of the lunar months elapsed 486 // int conjunctionDay = dayTohu + 29 * monthsElapsed + hoursElapsed / 24; 487 // int conjunctionParts = 1080 * (hoursElapsed % 24) + partsElapsed % 1080; 488 // return addDechiyos(year, conjunctionDay, conjunctionParts); 489 // } 490 491 /** 492 * Adds the 4 dechiyos for molad Tishrei. These are: 493 * <ol> 494 * <li>Lo ADU Rosh - Rosh Hashana can't fall on a Sunday, Wednesday or Friday. If the molad fell on one of these 495 * days, Rosh Hashana is delayed to the following day.</li> 496 * <li>Molad Zaken - If the molad of Tishrei falls after 12 noon, Rosh Hashana is delayed to the following day. If 497 * the following day is ADU, it will be delayed an additional day.</li> 498 * <li>GaTRaD - If on a non leap year the molad of Tishrei falls on a Tuesday (Ga) on or after 9 hours (T) and 204 499 * chalakim (TRaD) it is delayed till Thursday (one day delay, plus one day for Lo ADU Rosh)</li> 500 * <li>BeTuTaKFoT - if the year following a leap year falls on a Monday (Be) on or after 15 hours (Tu) and 589 501 * chalakim (TaKFoT) it is delayed till Tuesday</li> 502 * </ol> 503 * 504 * @param year the year 505 * @param moladDay the molad day 506 * @param moladParts the molad parts 507 * @return the number of elapsed days in the JewishCalendar adjusted for the 4 dechiyos. 508 */ 509 private static int addDechiyos(int year, int moladDay, int moladParts) { 510 int roshHashanaDay = moladDay; // if no dechiyos 511 // delay Rosh Hashana for the dechiyos of the Molad - new moon 1 - Molad Zaken, 2- GaTRaD 3- BeTuTaKFoT 512 if ((moladParts >= 19440) // Dechiya of Molad Zaken - molad is >= midday (18 hours * 1080 chalakim) 513 || (((moladDay % 7) == 2) // start Dechiya of GaTRaD - Ga = is a Tuesday 514 && (moladParts >= 9924) // TRaD = 9 hours, 204 parts or later (9 * 1080 + 204) 515 && !isJewishLeapYear(year)) // of a non-leap year - end Dechiya of GaTRaD 516 || (((moladDay % 7) == 1) // start Dechiya of BeTuTaKFoT - Be = is on a Monday 517 && (moladParts >= 16789) // TRaD = 15 hours, 589 parts or later (15 * 1080 + 589) 518 && (isJewishLeapYear(year - 1)))) { // in a year following a leap year - end Dechiya of BeTuTaKFoT 519 roshHashanaDay += 1; // Then postpone Rosh HaShanah one day 520 } 521 // start 4th Dechiya - Lo ADU Rosh - Rosh Hashana can't occur on A- sunday, D- Wednesday, U - Friday 522 if (((roshHashanaDay % 7) == 0)// If Rosh HaShanah would occur on Sunday, 523 || ((roshHashanaDay % 7) == 3) // or Wednesday, 524 || ((roshHashanaDay % 7) == 5)) { // or Friday - end 4th Dechiya - Lo ADU Rosh 525 roshHashanaDay = roshHashanaDay + 1; // Then postpone it one (more) day 526 } 527 return roshHashanaDay; 528 } 529 530 /** 531 * Returns the number of chalakim (parts - 1080 to the hour) from the original hypothetical Molad Tohu to the year 532 * and month passed in. 533 * 534 * @param year 535 * the Jewish year 536 * @param month 537 * the Jewish month the Jewish month, with the month numbers starting from Nisan. Use the JewishDate 538 * constants such as {@link JewishDate#TISHREI}. 539 * @return the number of chalakim (parts - 1080 to the hour) from the original hypothetical Molad Tohu 540 */ 541 private static long getChalakimSinceMoladTohu(int year, int month) { 542 // Jewish lunar month = 29 days, 12 hours and 793 chalakim 543 // chalakim since Molad Tohu BeHaRaD - 1 day, 5 hours and 204 chalakim 544 int monthOfYear = getJewishMonthOfYear(year, month); 545 int monthsElapsed = (235 * ((year - 1) / 19)) // Months in complete 19 year lunar (Metonic) cycles so far 546 + (12 * ((year - 1) % 19)) // Regular months in this cycle 547 + ((7 * ((year - 1) % 19) + 1) / 19) // Leap months this cycle 548 + (monthOfYear - 1); // add elapsed months till the start of the molad of the month 549 // return chalakim prior to BeHaRaD + number of chalakim since 550 return CHALAKIM_MOLAD_TOHU + (CHALAKIM_PER_MONTH * monthsElapsed); 551 } 552 553 /** 554 * Returns the number of chalakim (parts - 1080 to the hour) from the original hypothetical Molad Tohu to the Jewish 555 * year and month that this Object is set to. 556 * 557 * @return the number of chalakim (parts - 1080 to the hour) from the original hypothetical Molad Tohu 558 */ 559 public long getChalakimSinceMoladTohu() { 560 return getChalakimSinceMoladTohu(jewishYear, jewishMonth); 561 } 562 563 /** 564 * Converts the {@link JewishDate#NISSAN} based constants used by this class to numeric month starting from 565 * {@link JewishDate#TISHREI}. This is required for Molad claculations. 566 * 567 * @param year 568 * The Jewish year 569 * @param month 570 * The Jewish Month 571 * @return the Jewish month of the year starting with Tishrei 572 */ 573 private static int getJewishMonthOfYear(int year, int month) { 574 boolean isLeapYear = isJewishLeapYear(year); 575 return (month + (isLeapYear ? 6 : 5)) % (isLeapYear ? 13 : 12) + 1; 576 } 577 578 /** 579 * Validates the components of a Jewish date for validity. It will throw an {@link IllegalArgumentException} if the 580 * Jewish date is earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a 581 * {@link #isJewishLeapYear(int) leap year}), the day of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 582 * or > 59 or chalakim < 0 or > 17. For larger a larger number of chalakim such as 793 (TaShTzaG) break the chalakim into 583 * minutes (18 chalakim per minutes, so it would be 44 minutes and 1 chelek in the case of 793/TaShTzaG). 584 * 585 * @param year 586 * the Jewish year to validate. It will reject any year <= 3761 (lower than the year 1 Gregorian). 587 * @param month 588 * the Jewish month to validate. It will reject a month < 1 or > 12 (or 13 on a leap year) . 589 * @param dayOfMonth 590 * the day of the Jewish month to validate. It will reject any value < 1 or > 30 TODO: check calling 591 * methods to see if there is any reason that the class can validate that 30 is invalid for some months. 592 * @param hours 593 * the hours (for molad calculations). It will reject an hour < 0 or > 23 594 * @param minutes 595 * the minutes (for molad calculations). It will reject a minute < 0 or > 59 596 * @param chalakim 597 * the chalakim/parts (for molad calculations). It will reject a chalakim < 0 or > 17. For larger numbers 598 * such as 793 (TaShTzaG) break the chalakim into minutes (18 chalakim per minutes, so it would be 44 599 * minutes and 1 chelek in the case of 793/TaShTzaG) 600 * 601 * @throws IllegalArgumentException 602 * if a A Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a 603 * leap year), the day of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 or > 59 or 604 * chalakim < 0 or > 17. For larger a larger number of chalakim such as 793 (TaShTzaG) break the chalakim 605 * into minutes (18 chalakim per minutes, so it would be 44 minutes and 1 chelek in the case of 793 (TaShTzaG). 606 */ 607 private static void validateJewishDate(int year, int month, int dayOfMonth, int hours, int minutes, int chalakim) { 608 if (month < NISSAN || month > getLastMonthOfJewishYear(year)) { 609 throw new IllegalArgumentException("The Jewish month has to be between 1 and 12 (or 13 on a leap year). " 610 + month + " is invalid for the year " + year + "."); 611 } 612 if (dayOfMonth < 1 || dayOfMonth > 30) { 613 throw new IllegalArgumentException("The Jewish day of month can't be < 1 or > 30. " + dayOfMonth 614 + " is invalid."); 615 } 616 // reject dates prior to 18 Teves, 3761 (1/1/1 AD). This restriction can be relaxed if the date coding is 617 // changed/corrected 618 if ((year < 3761) || (year == 3761 && (month >= TISHREI && month < TEVES)) 619 || (year == 3761 && month == TEVES && dayOfMonth < 18)) { 620 throw new IllegalArgumentException( 621 "A Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian) can't be set. " + year + ", " + month 622 + ", " + dayOfMonth + " is invalid."); 623 } 624 if (hours < 0 || hours > 23) { 625 throw new IllegalArgumentException("Hours < 0 or > 23 can't be set. " + hours + " is invalid."); 626 } 627 628 if (minutes < 0 || minutes > 59) { 629 throw new IllegalArgumentException("Minutes < 0 or > 59 can't be set. " + minutes + " is invalid."); 630 } 631 632 if (chalakim < 0 || chalakim > 17) { 633 throw new IllegalArgumentException( 634 "Chalakim/parts < 0 or > 17 can't be set. " 635 + chalakim 636 + " is invalid. For larger numbers such as 793 (TaShTzaG) break the chalakim into minutes (18 chalakim per minutes, so it would be 44 minutes and 1 chelek in the case of 793 (TaShTzaG)"); 637 } 638 } 639 640 /** 641 * Validates the components of a Gregorian date for validity. It will throw an {@link IllegalArgumentException} if a 642 * year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in. 643 * 644 * @param year 645 * the Gregorian year to validate. It will reject any year < 1. 646 * @param month 647 * the Gregorian month number to validate. It will enforce that the month is between 0 - 11 like a 648 * {@link GregorianCalendar}, where {@link Calendar#JANUARY} has a value of 0. 649 * @param dayOfMonth 650 * the day of the Gregorian month to validate. It will reject any value < 1, but will allow values > 31 651 * since calling methods will simply set it to the maximum for that month. TODO: check calling methods to 652 * see if there is any reason that the class needs days > the maximum. 653 * @throws IllegalArgumentException 654 * if a year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in 655 * @see #validateGregorianYear(int) 656 * @see #validateGregorianMonth(int) 657 * @see #validateGregorianDayOfMonth(int) 658 */ 659 private static void validateGregorianDate(int year, int month, int dayOfMonth) { 660 validateGregorianMonth(month); 661 validateGregorianDayOfMonth(dayOfMonth); 662 validateGregorianYear(year); 663 } 664 665 /** 666 * Validates a Gregorian month for validity. 667 * 668 * @param month 669 * the Gregorian month number to validate. It will enforce that the month is between 0 - 11 like a 670 * {@link GregorianCalendar}, where {@link Calendar#JANUARY} has a value of 0. 671 */ 672 private static void validateGregorianMonth(int month) { 673 if (month > 11 || month < 0) { 674 throw new IllegalArgumentException("The Gregorian month has to be between 0 - 11. " + month 675 + " is invalid."); 676 } 677 } 678 679 /** 680 * Validates a Gregorian day of month for validity. 681 * 682 * @param dayOfMonth 683 * the day of the Gregorian month to validate. It will reject any value < 1, but will allow values > 31 684 * since calling methods will simply set it to the maximum for that month. TODO: check calling methods to 685 * see if there is any reason that the class needs days > the maximum. 686 */ 687 private static void validateGregorianDayOfMonth(int dayOfMonth) { 688 if (dayOfMonth <= 0) { 689 throw new IllegalArgumentException("The day of month can't be less than 1. " + dayOfMonth + " is invalid."); 690 } 691 } 692 693 /** 694 * Validates a Gregorian year for validity. 695 * 696 * @param year 697 * the Gregorian year to validate. It will reject any year < 1. 698 */ 699 private static void validateGregorianYear(int year) { 700 if (year < 1) { 701 throw new IllegalArgumentException("Years < 1 can't be claculated. " + year + " is invalid."); 702 } 703 } 704 705 /** 706 * Returns the number of days for a given Jewish year. ND+ER 707 * 708 * @param year 709 * the Jewish year 710 * @return the number of days for a given Jewish year. 711 * @see #isCheshvanLong() 712 * @see #isKislevShort() 713 */ 714 public static int getDaysInJewishYear(int year) { 715 return getJewishCalendarElapsedDays(year + 1) - getJewishCalendarElapsedDays(year); 716 } 717 718 /** 719 * Returns the number of days for the current year that the calendar is set to. 720 * 721 * @return the number of days for the Object's current Jewish year. 722 * @see #isCheshvanLong() 723 * @see #isKislevShort() 724 * @see #isJewishLeapYear() 725 */ 726 public int getDaysInJewishYear() { 727 return getDaysInJewishYear(getJewishYear()); 728 } 729 730 /** 731 * Returns if Cheshvan is long in a given Jewish year. The method name isLong is done since in a Kesidran (ordered) 732 * year Cheshvan is short. ND+ER 733 * 734 * @param year 735 * the year 736 * @return true if Cheshvan is long in Jewish year. 737 * @see #isCheshvanLong() 738 * @see #getCheshvanKislevKviah() 739 */ 740 private static boolean isCheshvanLong(int year) { 741 return getDaysInJewishYear(year) % 10 == 5; 742 } 743 744 /** 745 * Returns if Cheshvan is long (30 days VS 29 days) for the current year that the calendar is set to. The method 746 * name isLong is done since in a Kesidran (ordered) year Cheshvan is short. 747 * 748 * @return true if Cheshvan is long for the current year that the calendar is set to 749 * @see #isCheshvanLong() 750 */ 751 public boolean isCheshvanLong() { 752 return isCheshvanLong(getJewishYear()); 753 } 754 755 /** 756 * Returns if Kislev is short (29 days VS 30 days) in a given Jewish year. The method name isShort is done since in 757 * a Kesidran (ordered) year Kislev is long. ND+ER 758 * 759 * @param year 760 * the Jewish year 761 * @return true if Kislev is short for the given Jewish year. 762 * @see #isKislevShort() 763 * @see #getCheshvanKislevKviah() 764 */ 765 private static boolean isKislevShort(int year) { 766 return getDaysInJewishYear(year) % 10 == 3; 767 } 768 769 /** 770 * Returns if the Kislev is short for the year that this class is set to. The method name isShort is done since in a 771 * Kesidran (ordered) year Kislev is long. 772 * 773 * @return true if Kislev is short for the year that this class is set to 774 */ 775 public boolean isKislevShort() { 776 return isKislevShort(getJewishYear()); 777 } 778 779 /** 780 * Returns the Cheshvan and Kislev kviah (whether a Jewish year is short, regular or long). It will return 781 * {@link #SHELAIMIM} if both cheshvan and kislev are 30 days, {@link #KESIDRAN} if Cheshvan is 29 days and Kislev 782 * is 30 days and {@link #CHASERIM} if both are 29 days. 783 * 784 * @return {@link #SHELAIMIM} if both cheshvan and kislev are 30 days, {@link #KESIDRAN} if Cheshvan is 29 days and 785 * Kislev is 30 days and {@link #CHASERIM} if both are 29 days. 786 * @see #isCheshvanLong() 787 * @see #isKislevShort() 788 */ 789 public int getCheshvanKislevKviah() { 790 if (isCheshvanLong() && !isKislevShort()) { 791 return SHELAIMIM; 792 } else if (!isCheshvanLong() && isKislevShort()) { 793 return CHASERIM; 794 } else { 795 return KESIDRAN; 796 } 797 } 798 799 /** 800 * Returns the number of days of a Jewish month for a given month and year. 801 * 802 * @param month 803 * the Jewish month 804 * @param year 805 * the Jewish Year 806 * @return the number of days for a given Jewish month 807 */ 808 private static int getDaysInJewishMonth(int month, int year) { 809 if ((month == IYAR) || (month == TAMMUZ) || (month == ELUL) || ((month == CHESHVAN) && !(isCheshvanLong(year))) 810 || ((month == KISLEV) && isKislevShort(year)) || (month == TEVES) 811 || ((month == ADAR) && !(isJewishLeapYear(year))) || (month == ADAR_II)) { 812 return 29; 813 } else { 814 return 30; 815 } 816 } 817 818 /** 819 * Returns the number of days of the Jewish month that the calendar is currently set to. 820 * 821 * @return the number of days for the Jewish month that the calendar is currently set to. 822 */ 823 public int getDaysInJewishMonth() { 824 return getDaysInJewishMonth(getJewishMonth(), getJewishYear()); 825 } 826 827 /** 828 * Computes the Jewish date from the absolute date. 829 */ 830 private void absDateToJewishDate() { 831 // Approximation from below 832 jewishYear = (gregorianAbsDate - JEWISH_EPOCH) / 366; 833 // Search forward for year from the approximation 834 while (gregorianAbsDate >= jewishDateToAbsDate(jewishYear + 1, TISHREI, 1)) { 835 jewishYear++; 836 } 837 // Search forward for month from either Tishri or Nisan. 838 if (gregorianAbsDate < jewishDateToAbsDate(jewishYear, NISSAN, 1)) { 839 jewishMonth = TISHREI;// Start at Tishri 840 } else { 841 jewishMonth = NISSAN;// Start at Nisan 842 } 843 while (gregorianAbsDate > jewishDateToAbsDate(jewishYear, jewishMonth, getDaysInJewishMonth())) { 844 jewishMonth++; 845 } 846 // Calculate the day by subtraction 847 jewishDay = gregorianAbsDate - jewishDateToAbsDate(jewishYear, jewishMonth, 1) + 1; 848 } 849 850 /** 851 * Returns the absolute date of Jewish date. ND+ER 852 * 853 * @param year 854 * the Jewish year. The year can't be negative 855 * @param month 856 * the Jewish month starting with Nisan. Nisan expects a value of 1 etc till Adar with a value of 12. For 857 * a leap year, 13 will be the expected value for Adar II. Use the constants {@link JewishDate#NISSAN} 858 * etc. 859 * @param dayOfMonth 860 * the Jewish day of month. valid values are 1-30. If the day of month is set to 30 for a month that only 861 * has 29 days, the day will be set as 29. 862 * @return the absolute date of the Jewish date. 863 */ 864 private static int jewishDateToAbsDate(int year, int month, int dayOfMonth) { 865 int elapsed = getDaysSinceStartOfJewishYear(year, month, dayOfMonth); 866 // add elapsed days this year + Days in prior years + Days elapsed before absolute year 1 867 return elapsed + getJewishCalendarElapsedDays(year) + JEWISH_EPOCH; 868 } 869 870 /** 871 * Returns the molad for a given year and month. Returns a JewishDate {@link Object} set to the date of the molad 872 * with the {@link #getMoladHours() hours}, {@link #getMoladMinutes() minutes} and {@link #getMoladChalakim() 873 * chalakim} set. In the current implementation, it sets the molad time based on a midnight date rollover. This 874 * means that Rosh Chodesh Adar II, 5771 with a molad of 7 chalakim past midnight on Shabbos 29 Adar I / March 5, 875 * 2011 12:00 AM and 7 chalakim, will have the following values: hours: 0, minutes: 0, Chalakim: 7. 876 * 877 * @return a JewishDate {@link Object} set to the date of the molad with the {@link #getMoladHours() hours}, 878 * {@link #getMoladMinutes() minutes} and {@link #getMoladChalakim() chalakim} set. 879 */ 880 public JewishDate getMolad() { 881 JewishDate moladDate = new JewishDate(getChalakimSinceMoladTohu()); 882 if (moladDate.getMoladHours() >= 6) { 883 moladDate.forward(Calendar.DATE, 1); 884 } 885 moladDate.setMoladHours((moladDate.getMoladHours() + 18) % 24); 886 return moladDate; 887 } 888 889 /** 890 * Returns the number of days from the Jewish epoch from the number of chalakim from the epoch passed in. 891 * 892 * @param chalakim 893 * the number of chalakim since the beginning of Sunday prior to BaHaRaD 894 * @return the number of days from the Jewish epoch 895 */ 896 private static int moladToAbsDate(long chalakim) { 897 return (int) (chalakim / CHALAKIM_PER_DAY) + JEWISH_EPOCH; 898 } 899 900 /** 901 * Constructor that creates a JewishDate based on a molad passed in. The molad would be the number of chalakim/parts 902 * starting at the beginning of Sunday prior to the molad Tohu BeHaRaD (Be = Monday, Ha= 5 hours and Rad =204 903 * chalakim/parts) - prior to the start of the Jewish calendar. BeHaRaD is 23:11:20 on Sunday night(5 hours 204/1080 904 * chalakim after sunset on Sunday evening). 905 * 906 * @param molad the number of chalakim since the beginning of Sunday prior to BaHaRaD 907 */ 908 public JewishDate(long molad) { 909 absDateToDate(moladToAbsDate(molad)); 910 // long chalakimSince = getChalakimSinceMoladTohu(year, TISHREI);// tishrei 911 int conjunctionDay = (int) (molad / (long) CHALAKIM_PER_DAY); 912 int conjunctionParts = (int) (molad - conjunctionDay * (long) CHALAKIM_PER_DAY); 913 setMoladTime(conjunctionParts); 914 } 915 916 /** 917 * Sets the molad time (hours minutes and chalakim) based on the number of chalakim since the start of the day. 918 * 919 * @param chalakim 920 * the number of chalakim since the start of the day. 921 */ 922 private void setMoladTime(int chalakim) { 923 int adjustedChalakim = chalakim; 924 setMoladHours(adjustedChalakim / CHALAKIM_PER_HOUR); 925 adjustedChalakim = adjustedChalakim - (getMoladHours() * CHALAKIM_PER_HOUR); 926 setMoladMinutes(adjustedChalakim / CHALAKIM_PER_MINUTE); 927 setMoladChalakim(adjustedChalakim - moladMinutes * CHALAKIM_PER_MINUTE); 928 } 929 930 /** 931 * returns the number of days from Rosh Hashana of the date passed in, to the full date passed in. 932 * 933 * @param year 934 * the Jewish year 935 * @param month 936 * the Jewish month 937 * @param dayOfMonth 938 * the day in the Jewish month 939 * @return the number of days 940 */ 941 private static int getDaysSinceStartOfJewishYear(int year, int month, int dayOfMonth) { 942 int elapsedDays = dayOfMonth; 943 // Before Tishrei (from Nissan to Tishrei), add days in prior months 944 if (month < TISHREI) { 945 // this year before and after Nisan. 946 for (int m = TISHREI; m <= getLastMonthOfJewishYear(year); m++) { 947 elapsedDays += getDaysInJewishMonth(m, year); 948 } 949 for (int m = NISSAN; m < month; m++) { 950 elapsedDays += getDaysInJewishMonth(m, year); 951 } 952 } else { // Add days in prior months this year 953 for (int m = TISHREI; m < month; m++) { 954 elapsedDays += getDaysInJewishMonth(m, year); 955 } 956 } 957 return elapsedDays; 958 } 959 960 /** 961 * returns the number of days from Rosh Hashana of the date passed in, to the full date passed in. 962 * 963 * @return the number of days 964 */ 965 public int getDaysSinceStartOfJewishYear() { 966 return getDaysSinceStartOfJewishYear(getJewishYear(), getJewishMonth(), getJewishDayOfMonth()); 967 } 968 969 /** 970 * Creates a Jewish date based on a Jewish year, month and day of month. 971 * 972 * @param jewishYear 973 * the Jewish year 974 * @param jewishMonth 975 * the Jewish month. The method expects a 1 for Nissan ... 12 for Adar and 13 for Adar II. Use the 976 * constants {@link #NISSAN} ... {@link #ADAR} (or {@link #ADAR_II} for a leap year Adar II) to avoid any 977 * confusion. 978 * @param jewishDayOfMonth 979 * the Jewish day of month. If 30 is passed in for a month with only 29 days (for example {@link #IYAR}, 980 * or {@link #KISLEV} in a year that {@link #isKislevShort()}), the 29th (last valid date of the month) 981 * will be set 982 * @throws IllegalArgumentException 983 * if the day of month is < 1 or > 30, or a year of < 0 is passed in. 984 */ 985 public JewishDate(int jewishYear, int jewishMonth, int jewishDayOfMonth) { 986 setJewishDate(jewishYear, jewishMonth, jewishDayOfMonth); 987 } 988 989 /** 990 * Default constructor will set a default date to the current system date. 991 */ 992 public JewishDate() { 993 resetDate(); 994 } 995 996 /** 997 * A constructor that initializes the date to the {@link java.util.Date Date} paremeter. 998 * 999 * @param date 1000 * the <code>Date</code> to set the calendar to 1001 * @throws IllegalArgumentException 1002 * if the date would fall prior to the January 1, 1 AD 1003 */ 1004 public JewishDate(Date date) { 1005 setDate(date); 1006 } 1007 1008 /** 1009 * A constructor that initializes the date to the {@link java.util.Calendar Calendar} paremeter. 1010 * 1011 * @param calendar 1012 * the <code>Calendar</code> to set the calendar to 1013 * @throws IllegalArgumentException 1014 * if the {@link Calendar#ERA} is {@link GregorianCalendar#BC} 1015 */ 1016 public JewishDate(Calendar calendar) { 1017 setDate(calendar); 1018 } 1019 1020 /** 1021 * A constructor that initializes the date to the {@link java.time.LocalDate LocalDate} paremeter. 1022 * 1023 * @param localDate 1024 * the <code>LocalDate</code> to set the calendar to 1025 * @throws IllegalArgumentException 1026 * if the {@link Calendar#ERA} is {@link GregorianCalendar#BC} 1027 */ 1028 public JewishDate(LocalDate localDate) { 1029 setDate(localDate); 1030 } 1031 1032 /** 1033 * Sets the date based on a {@link java.util.Calendar Calendar} object. Modifies the Jewish date as well. 1034 * 1035 * @param calendar 1036 * the <code>Calendar</code> to set the calendar to 1037 * @throws IllegalArgumentException 1038 * if the {@link Calendar#ERA} is {@link GregorianCalendar#BC} 1039 */ 1040 public void setDate(Calendar calendar) { 1041 if (calendar.get(Calendar.ERA) == GregorianCalendar.BC) { 1042 throw new IllegalArgumentException("Calendars with a BC era are not supported. The year " 1043 + calendar.get(Calendar.YEAR) + " BC is invalid."); 1044 } 1045 gregorianMonth = calendar.get(Calendar.MONTH) + 1; 1046 gregorianDayOfMonth = calendar.get(Calendar.DATE); 1047 gregorianYear = calendar.get(Calendar.YEAR); 1048 gregorianAbsDate = gregorianDateToAbsDate(gregorianYear, gregorianMonth, gregorianDayOfMonth); // init the date 1049 absDateToJewishDate(); 1050 1051 dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1; // set day of week 1052 } 1053 1054 /** 1055 * Sets the date based on a {@link java.util.Date Date} object. Modifies the Jewish date as well. 1056 * 1057 * @param date 1058 * the <code>Date</code> to set the calendar to 1059 * @throws IllegalArgumentException 1060 * if the date would fall prior to the year 1 AD 1061 */ 1062 public void setDate(Date date) { 1063 Calendar cal = Calendar.getInstance(); 1064 cal.setTime(date); 1065 setDate(cal); 1066 } 1067 1068 /** 1069 * Sets the date based on a {@link java.time.LocalDate LocalDate} object. Modifies the Jewish date as well. 1070 * 1071 * @param localDate 1072 * the <code>LocalDate</code> to set the calendar to 1073 * @throws IllegalArgumentException 1074 * if the date would fall prior to the year 1 AD 1075 */ 1076 public void setDate(LocalDate localDate) { 1077 Calendar cal = Calendar.getInstance(); 1078 cal.set(localDate.getYear(), localDate.getMonthValue() - 1, localDate.getDayOfMonth()); 1079 setDate(cal); 1080 } 1081 1082 /** 1083 * Sets the Gregorian Date, and updates the Jewish date accordingly. Like the Java Calendar A value of 0 is expected 1084 * for January. 1085 * 1086 * @param year 1087 * the Gregorian year 1088 * @param month 1089 * the Gregorian month. Like the Java Calendar, this class expects 0 for January 1090 * @param dayOfMonth 1091 * the Gregorian day of month. If this is > the number of days in the month/year, the last valid date of 1092 * the month will be set 1093 * @throws IllegalArgumentException 1094 * if a year of < 1, a month < 0 or > 11 or a day of month < 1 is passed in 1095 */ 1096 public void setGregorianDate(int year, int month, int dayOfMonth) { 1097 validateGregorianDate(year, month, dayOfMonth); 1098 setInternalGregorianDate(year, month + 1, dayOfMonth); 1099 } 1100 1101 /** 1102 * Sets the hidden internal representation of the Gregorian date , and updates the Jewish date accordingly. While 1103 * public getters and setters have 0 based months matching the Java Calendar classes, This class internally 1104 * represents the Gregorian month starting at 1. When this is called it will not adjust the month to match the Java 1105 * Calendar classes. 1106 * 1107 * @param year the year 1108 * @param month the month 1109 * @param dayOfMonth the day of month 1110 */ 1111 private void setInternalGregorianDate(int year, int month, int dayOfMonth) { 1112 // make sure date is a valid date for the given month, if not, set to last day of month 1113 if (dayOfMonth > getLastDayOfGregorianMonth(month, year)) { 1114 dayOfMonth = getLastDayOfGregorianMonth(month, year); 1115 } 1116 // init month, date, year 1117 gregorianMonth = month; 1118 gregorianDayOfMonth = dayOfMonth; 1119 gregorianYear = year; 1120 1121 gregorianAbsDate = gregorianDateToAbsDate(gregorianYear, gregorianMonth, gregorianDayOfMonth); // init date 1122 absDateToJewishDate(); 1123 1124 dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1; // set day of week 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 Nisan. 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 * @throws IllegalArgumentException 1140 * if a A Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a 1141 * leap year) or the day of month is < 1 or > 30 is passed in 1142 */ 1143 public void setJewishDate(int year, int month, int dayOfMonth) { 1144 setJewishDate(year, month, dayOfMonth, 0, 0, 0); 1145 } 1146 1147 /** 1148 * Sets the Jewish Date and updates the Gregorian date accordingly. 1149 * 1150 * @param year 1151 * the Jewish year. The year can't be negative 1152 * @param month 1153 * the Jewish month starting with Nisan. A value of 1 is expected for Nissan ... 12 for Adar and 13 for 1154 * Adar II. Use the constants {@link #NISSAN} ... {@link #ADAR} (or {@link #ADAR_II} for a leap year Adar 1155 * II) to avoid any confusion. 1156 * @param dayOfMonth 1157 * the Jewish day of month. valid values are 1-30. If the day of month is set to 30 for a month that only 1158 * has 29 days, the day will be set as 29. 1159 * 1160 * @param hours 1161 * the hour of the day. Used for Molad calculations 1162 * @param minutes 1163 * the minutes. Used for Molad calculations 1164 * @param chalakim 1165 * the chalakim/parts. Used for Molad calculations. The chalakim should not exceed 17. Minutes should be 1166 * used for larger numbers. 1167 * 1168 * @throws IllegalArgumentException 1169 * if a A Jewish date earlier than 18 Teves, 3761 (1/1/1 Gregorian), a month < 1 or > 12 (or 13 on a 1170 * leap year), the day of month is < 1 or > 30, an hour < 0 or > 23, a minute < 0 > 59 or chalakim < 0 > 1171 * 17. For larger a larger number of chalakim such as 793 (TaShTzaG) break the chalakim into minutes (18 1172 * chalakim per minutes, so it would be 44 minutes and 1 chelek in the case of 793 (TaShTzaG). 1173 */ 1174 public void setJewishDate(int year, int month, int dayOfMonth, int hours, int minutes, int chalakim) { 1175 validateJewishDate(year, month, dayOfMonth, hours, minutes, chalakim); 1176 1177 // if 30 is passed for a month that only has 29 days (for example by rolling the month from a month that had 30 1178 // days to a month that only has 29) set the date to 29th 1179 if (dayOfMonth > getDaysInJewishMonth(month, year)) { 1180 dayOfMonth = getDaysInJewishMonth(month, year); 1181 } 1182 1183 jewishMonth = month; 1184 jewishDay = dayOfMonth; 1185 jewishYear = year; 1186 moladHours = hours; 1187 moladMinutes = minutes; 1188 moladChalakim = chalakim; 1189 1190 gregorianAbsDate = jewishDateToAbsDate(jewishYear, jewishMonth, jewishDay); // reset Gregorian date 1191 absDateToDate(gregorianAbsDate); 1192 1193 dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1; // reset day of week 1194 } 1195 1196 /** 1197 * Returns this object's date as a {@link java.util.Calendar} object. 1198 * 1199 * @return The {@link java.util.Calendar} 1200 */ 1201 public Calendar getGregorianCalendar() { 1202 Calendar calendar = Calendar.getInstance(); 1203 calendar.set(getGregorianYear(), getGregorianMonth(), getGregorianDayOfMonth()); 1204 return calendar; 1205 } 1206 1207 /** 1208 * Returns this object's date as a {@link java.time.LocalDate} object. 1209 * 1210 * @return The {@link java.time.LocalDate} 1211 */ 1212 public LocalDate getLocalDate() { 1213 return LocalDate.of(getGregorianYear(), getGregorianMonth() + 1, getGregorianDayOfMonth()); 1214 } 1215 1216 /** 1217 * Resets this date to the current system date. 1218 */ 1219 public void resetDate() { 1220 Calendar calendar = Calendar.getInstance(); 1221 setDate(calendar); 1222 } 1223 1224 /** 1225 * Returns a string containing the Jewish date in the form, "day Month, year" e.g. "21 Shevat, 5729". For more 1226 * complex formatting, use the formatter classes. 1227 * 1228 * @return the Jewish date in the form "day Month, year" e.g. "21 Shevat, 5729" 1229 * @see HebrewDateFormatter#format(JewishDate) 1230 */ 1231 public String toString() { 1232 return new HebrewDateFormatter().format(this); 1233 } 1234 1235 /** 1236 * Rolls the date, month or year forward by the amount passed in. It modifies both the Gregorian and Jewish dates accordingly. 1237 * If manipulation beyond the fields supported here is required, use the {@link Calendar} class {@link Calendar#add(int, int)} 1238 * or {@link Calendar#roll(int, int)} methods in the following manner. 1239 * 1240 * <pre> 1241 * <code> 1242 * Calendar cal = jewishDate.getTime(); // get a java.util.Calendar representation of the JewishDate 1243 * cal.add(Calendar.MONTH, 3); // add 3 Gregorian months 1244 * jewishDate.setDate(cal); // set the updated calendar back to this class 1245 * </code> 1246 * </pre> 1247 * 1248 * @param field the calendar field to be forwarded. The must be {@link Calendar#DATE}, {@link Calendar#MONTH} or {@link Calendar#YEAR} 1249 * @param amount the positive amount to move forward 1250 * @throws IllegalArgumentException if the field is anything besides {@link Calendar#DATE}, {@link Calendar#MONTH} or {@link Calendar#YEAR} 1251 * or if the amount is less than 1 1252 * 1253 * @see #back() 1254 * @see Calendar#add(int, int) 1255 * @see Calendar#roll(int, int) 1256 */ 1257 public void forward(int field, int amount) { 1258 if (field != Calendar.DATE && field != Calendar.MONTH && field != Calendar.YEAR) { 1259 throw new IllegalArgumentException("Unsupported field was passed to Forward. Only Calendar.DATE, Calendar.MONTH or Calendar.YEAR are supported."); 1260 } 1261 if (amount < 1) { 1262 throw new IllegalArgumentException("JewishDate.forward() does not support amounts less than 1. See JewishDate.back()"); 1263 } 1264 if (field == Calendar.DATE) { 1265 // Change Gregorian date 1266 for (int i = 0; i < amount; i++) { 1267 if (gregorianDayOfMonth == getLastDayOfGregorianMonth(gregorianMonth, gregorianYear)) { 1268 gregorianDayOfMonth = 1; 1269 // if last day of year 1270 if (gregorianMonth == 12) { 1271 gregorianYear++; 1272 gregorianMonth = 1; 1273 } else { 1274 gregorianMonth++; 1275 } 1276 } else { // if not last day of month 1277 gregorianDayOfMonth++; 1278 } 1279 1280 // Change the Jewish Date 1281 if (jewishDay == getDaysInJewishMonth()) { 1282 // if it last day of elul (i.e. last day of Jewish year) 1283 if (jewishMonth == ELUL) { 1284 jewishYear++; 1285 jewishMonth++; 1286 jewishDay = 1; 1287 } else if (jewishMonth == getLastMonthOfJewishYear(jewishYear)) { 1288 // if it is the last day of Adar, or Adar II as case may be 1289 jewishMonth = NISSAN; 1290 jewishDay = 1; 1291 } else { 1292 jewishMonth++; 1293 jewishDay = 1; 1294 } 1295 } else { // if not last date of month 1296 jewishDay++; 1297 } 1298 1299 if (dayOfWeek == 7) { // if last day of week, loop back to Sunday 1300 dayOfWeek = 1; 1301 } else { 1302 dayOfWeek++; 1303 } 1304 1305 gregorianAbsDate++; // increment the absolute date 1306 } 1307 } else if (field == Calendar.MONTH) { 1308 forwardJewishMonth(amount); 1309 } else if (field == Calendar.YEAR) { 1310 setJewishYear(getJewishYear() + amount); 1311 } 1312 } 1313 1314 /** 1315 * Forward the Jewish date by the number of months passed in. 1316 * FIXME: Deal with forwarding a date such as 30 Nisan by a month. 30 Iyar does not exist. This should be dealt with similar to 1317 * the way that the Java Calendar behaves (not that simple since there is a difference between add() or roll(). 1318 * 1319 * @throws IllegalArgumentException if the amount is less than 1 1320 * @param amount the number of months to roll the month forward 1321 */ 1322 private void forwardJewishMonth(int amount) { 1323 if (amount < 1) { 1324 throw new IllegalArgumentException("the amount of months to forward has to be greater than zero."); 1325 } 1326 for (int i = 0; i < amount; i++) { 1327 if(getJewishMonth() == ELUL) { 1328 setJewishMonth(TISHREI); 1329 setJewishYear(getJewishYear() + 1); 1330 } else if ((! isJewishLeapYear() && getJewishMonth() == ADAR) 1331 || (isJewishLeapYear() && getJewishMonth() == ADAR_II)){ 1332 setJewishMonth(NISSAN); 1333 } else { 1334 setJewishMonth(getJewishMonth() + 1); 1335 } 1336 } 1337 } 1338 1339 /** 1340 * Rolls the date back by 1 day. It modifies both the Gregorian and Jewish dates accordingly. The API does not 1341 * currently offer the ability to forward more than one day at a time, or to forward by month or year. If such 1342 * manipulation is required use the {@link Calendar} class {@link Calendar#add(int, int)} or 1343 * {@link Calendar#roll(int, int)} methods in the following manner. 1344 * 1345 * <pre> 1346 * <code> 1347 * Calendar cal = jewishDate.getTime(); // get a java.util.Calendar representation of the JewishDate 1348 * cal.add(Calendar.MONTH, -3); // subtract 3 Gregorian months 1349 * jewishDate.setDate(cal); // set the updated calendar back to this class 1350 * </code> 1351 * </pre> 1352 * 1353 * @see #back() 1354 * @see Calendar#add(int, int) 1355 * @see Calendar#roll(int, int) 1356 */ 1357 public void back() { 1358 // Change Gregorian date 1359 if (gregorianDayOfMonth == 1) { // if first day of month 1360 if (gregorianMonth == 1) { // if first day of year 1361 gregorianMonth = 12; 1362 gregorianYear--; 1363 } else { 1364 gregorianMonth--; 1365 } 1366 // change to last day of previous month 1367 gregorianDayOfMonth = getLastDayOfGregorianMonth(gregorianMonth, gregorianYear); 1368 } else { 1369 gregorianDayOfMonth--; 1370 } 1371 // change Jewish date 1372 if (jewishDay == 1) { // if first day of the Jewish month 1373 if (jewishMonth == NISSAN) { 1374 jewishMonth = getLastMonthOfJewishYear(jewishYear); 1375 } else if (jewishMonth == TISHREI) { // if Rosh Hashana 1376 jewishYear--; 1377 jewishMonth--; 1378 } else { 1379 jewishMonth--; 1380 } 1381 jewishDay = getDaysInJewishMonth(); 1382 } else { 1383 jewishDay--; 1384 } 1385 1386 if (dayOfWeek == 1) { // if first day of week, loop back to Saturday 1387 dayOfWeek = 7; 1388 } else { 1389 dayOfWeek--; 1390 } 1391 gregorianAbsDate--; // change the absolute date 1392 } 1393 1394 /** 1395 * Indicates whether some other object is "equal to" this one. 1396 * @see Object#equals(Object) 1397 */ 1398 public boolean equals(Object object) { 1399 if (this == object) { 1400 return true; 1401 } 1402 if (!(object instanceof JewishDate)) { 1403 return false; 1404 } 1405 JewishDate jewishDate = (JewishDate) object; 1406 return gregorianAbsDate == jewishDate.getAbsDate(); 1407 } 1408 1409 /** 1410 * Compares two dates as per the compareTo() method in the Comparable interface. Returns a value less than 0 if this 1411 * date is "less than" (before) the date, greater than 0 if this date is "greater than" (after) the date, or 0 if 1412 * they are equal. 1413 */ 1414 public int compareTo(JewishDate jewishDate) { 1415 return Integer.compare(gregorianAbsDate, jewishDate.getAbsDate()); 1416 } 1417 1418 /** 1419 * Returns the Gregorian month (between 0-11). 1420 * 1421 * @return the Gregorian month (between 0-11). Like the java.util.Calendar, months are 0 based. 1422 */ 1423 public int getGregorianMonth() { 1424 return gregorianMonth - 1; 1425 } 1426 1427 /** 1428 * Returns the Gregorian day of the month. 1429 * 1430 * @return the Gregorian day of the mont 1431 */ 1432 public int getGregorianDayOfMonth() { 1433 return gregorianDayOfMonth; 1434 } 1435 1436 /** 1437 * Returns the Gregotian year. 1438 * 1439 * @return the Gregorian year 1440 */ 1441 public int getGregorianYear() { 1442 return gregorianYear; 1443 } 1444 1445 /** 1446 * Returns the Jewish month 1-12 (or 13 years in a leap year). The month count starts with 1 for Nisan and goes to 1447 * 13 for Adar II 1448 * 1449 * @return the Jewish month from 1 to 12 (or 13 years in a leap year). The month count starts with 1 for Nisan and 1450 * goes to 13 for Adar II 1451 */ 1452 public int getJewishMonth() { 1453 return jewishMonth; 1454 } 1455 1456 /** 1457 * Returns the Jewish day of month. 1458 * 1459 * @return the Jewish day of the month 1460 */ 1461 public int getJewishDayOfMonth() { 1462 return jewishDay; 1463 } 1464 1465 /** 1466 * Returns the Jewish year. 1467 * 1468 * @return the Jewish year 1469 */ 1470 public int getJewishYear() { 1471 return jewishYear; 1472 } 1473 1474 /** 1475 * Returns the day of the week as a number between 1-7. 1476 * 1477 * @return the day of the week as a number between 1-7. 1478 */ 1479 public int getDayOfWeek() { 1480 return dayOfWeek; 1481 } 1482 1483 /** 1484 * Sets the Gregorian month. 1485 * 1486 * @param month 1487 * the Gregorian month 1488 * 1489 * @throws IllegalArgumentException 1490 * if a month < 0 or > 11 is passed in 1491 */ 1492 public void setGregorianMonth(int month) { 1493 validateGregorianMonth(month); 1494 setInternalGregorianDate(gregorianYear, month + 1, gregorianDayOfMonth); 1495 } 1496 1497 /** 1498 * sets the Gregorian year. 1499 * 1500 * @param year 1501 * the Gregorian year. 1502 * @throws IllegalArgumentException 1503 * if a year of < 1 is passed in 1504 */ 1505 public void setGregorianYear(int year) { 1506 validateGregorianYear(year); 1507 setInternalGregorianDate(year, gregorianMonth, gregorianDayOfMonth); 1508 } 1509 1510 /** 1511 * sets the Gregorian Day of month. 1512 * 1513 * @param dayOfMonth 1514 * the Gregorian Day of month. 1515 * @throws IllegalArgumentException 1516 * if the day of month of < 1 is passed in 1517 */ 1518 public void setGregorianDayOfMonth(int dayOfMonth) { 1519 validateGregorianDayOfMonth(dayOfMonth); 1520 setInternalGregorianDate(gregorianYear, gregorianMonth, dayOfMonth); 1521 } 1522 1523 /** 1524 * sets the Jewish month. 1525 * 1526 * @param month 1527 * the Jewish month from 1 to 12 (or 13 years in a leap year). The month count starts with 1 for Nisan 1528 * and goes to 13 for Adar II 1529 * @throws IllegalArgumentException 1530 * if a month < 1 or > 12 (or 13 on a leap year) is passed in 1531 */ 1532 public void setJewishMonth(int month) { 1533 setJewishDate(jewishYear, month, jewishDay); 1534 } 1535 1536 /** 1537 * sets the Jewish year. 1538 * 1539 * @param year 1540 * the Jewish year 1541 * @throws IllegalArgumentException 1542 * if a year of < 3761 is passed in. The same will happen if the year is 3761 and the month and day 1543 * previously set are < 18 Teves (preior to Jan 1, 1 AD) 1544 */ 1545 public void setJewishYear(int year) { 1546 setJewishDate(year, jewishMonth, jewishDay); 1547 } 1548 1549 /** 1550 * sets the Jewish day of month. 1551 * 1552 * @param dayOfMonth 1553 * the Jewish day of month 1554 * @throws IllegalArgumentException 1555 * if the day of month is < 1 or > 30 is passed in 1556 */ 1557 public void setJewishDayOfMonth(int dayOfMonth) { 1558 setJewishDate(jewishYear, jewishMonth, dayOfMonth); 1559 } 1560 1561 /** 1562 * A method that creates a <a href="http://en.wikipedia.org/wiki/Object_copy#Deep_copy">deep copy</a> of the object. 1563 * 1564 * @see Object#clone() 1565 */ 1566 public Object clone() { 1567 JewishDate clone = null; 1568 try { 1569 clone = (JewishDate) super.clone(); 1570 } catch (CloneNotSupportedException cnse) { 1571 // Required by the compiler. Should never be reached since we implement clone() 1572 } 1573 clone.setInternalGregorianDate(gregorianYear, gregorianMonth, gregorianDayOfMonth); 1574 return clone; 1575 } 1576 1577 /** 1578 * Overrides {@link Object#hashCode()}. 1579 * @see Object#hashCode() 1580 */ 1581 public int hashCode() { 1582 int result = 17; 1583 result = 37 * result + getClass().hashCode(); // needed or this and subclasses will return identical hash 1584 result += 37 * result + gregorianAbsDate; 1585 return result; 1586 } 1587}