UNPKG

@hebcal/hdate

Version:

converts between Hebrew and Gregorian dates using Rata Die (R.D.) algorithm by Dershowitz and Reingold

190 lines (187 loc) 7.15 kB
/*! @hebcal/hdate v0.14.4, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */ import { hebrew2abs, longCheshvan, abs2hebrew, shortKislev, monthsInYear, isLeapYear, months } from './hdateBase.js'; import { abs2greg, isDate, greg2abs } from './greg.js'; const NISAN = months.NISAN; const CHESHVAN = months.CHESHVAN; const KISLEV = months.KISLEV; const TEVET = months.TEVET; const SHVAT = months.SHVAT; const ADAR_I = months.ADAR_I; const ADAR_II = months.ADAR_II; /** * Returns true if the object is a SimpleHebrewDate * @private */ function isSimpleHebrewDate(obj) { return (typeof obj === 'object' && obj !== null && typeof obj.yy === 'number' && typeof obj.mm === 'number' && typeof obj.dd === 'number'); } /** * @private */ function toSimpleHebrewDate(obj) { if (isSimpleHebrewDate(obj)) { return obj; } else if (isDate(obj)) { const abs = greg2abs(obj); return abs2hebrew(abs); } else { // typeof obj === 'number' return abs2hebrew(obj); } } /** * Calculates yahrzeit. * `hyear` must be after original `date` of death. * Returns `undefined` when requested year preceeds or is same as original year. * * Hebcal uses the algorithm defined in "Calendrical Calculations" * by Edward M. Reingold and Nachum Dershowitz. * * The customary anniversary date of a death is more complicated and depends * also on the character of the year in which the first anniversary occurs. * There are several cases: * * * If the date of death is Marcheshvan 30, the anniversary in general depends * on the first anniversary; if that first anniversary was not Marcheshvan 30, * use the day before Kislev 1. * * If the date of death is Kislev 30, the anniversary in general again depends * on the first anniversary — if that was not Kislev 30, use the day before * Tevet 1. * * If the date of death is Adar II, the anniversary is the same day in the * last month of the Hebrew year (Adar or Adar II). * * If the date of death is Adar I 30, the anniversary in a Hebrew year that * is not a leap year (in which Adar only has 29 days) is the last day in * Shevat. * * In all other cases, use the normal (that is, same month number) anniversary * of the date of death. [Calendrical Calculations p. 113] * @example * import {getYahrzeit} from '@hebcal/hdate'; * const dt = new Date(2014, 2, 2); // '2014-03-02' == '30 Adar I 5774' * const anniversary = getYahrzeit(5780, dt); // '2/25/2020' == '30 Sh\'vat 5780' * @param hyear Hebrew year * @param date Gregorian or Hebrew date of death * @returns anniversary occurring in `hyear` */ function getYahrzeit(hyear, date) { const hd = getYahrzeitHD(hyear, date); if (typeof hd === 'undefined') { return hd; } return abs2greg(hebrew2abs(hd.yy, hd.mm, hd.dd)); } function getYahrzeitHD(hyear, date) { let hDeath = toSimpleHebrewDate(date); if (hyear <= hDeath.yy) { // Hebrew year ${hyear} occurs on or before original date in ${hDeath.yy} return undefined; } if (hDeath.mm === CHESHVAN && hDeath.dd === 30 && !longCheshvan(hDeath.yy + 1)) { // If it's Heshvan 30 it depends on the first anniversary; // if that was not Heshvan 30, use the day before Kislev 1. hDeath = abs2hebrew(hebrew2abs(hyear, KISLEV, 1) - 1); } else if (hDeath.mm === KISLEV && hDeath.dd === 30 && shortKislev(hDeath.yy + 1)) { // If it's Kislev 30 it depends on the first anniversary; // if that was not Kislev 30, use the day before Teveth 1. hDeath = abs2hebrew(hebrew2abs(hyear, TEVET, 1) - 1); } else if (hDeath.mm === ADAR_II) { // If it's Adar II, use the same day in last month of year (Adar or Adar II). hDeath.mm = monthsInYear(hyear); } else if (hDeath.mm === ADAR_I && hDeath.dd === 30 && !isLeapYear(hyear)) { // If it's the 30th in Adar I and year is not a leap year // (so Adar has only 29 days), use the last day in Shevat. hDeath.dd = 30; hDeath.mm = SHVAT; } // In all other cases, use the normal anniversary of the date of death. // advance day to rosh chodesh if needed if (hDeath.mm === CHESHVAN && hDeath.dd === 30 && !longCheshvan(hyear)) { hDeath.mm = KISLEV; hDeath.dd = 1; } else if (hDeath.mm === KISLEV && hDeath.dd === 30 && shortKislev(hyear)) { hDeath.mm = TEVET; hDeath.dd = 1; } hDeath.yy = hyear; return hDeath; } /** * Calculates a birthday or anniversary (non-yahrzeit). * `hyear` must be after original `date` of anniversary. * Returns `undefined` when requested year preceeds or is same as original year. * * Hebcal uses the algorithm defined in "Calendrical Calculations" * by Edward M. Reingold and Nachum Dershowitz. * * The birthday of someone born in Adar of an ordinary year or Adar II of * a leap year is also always in the last month of the year, be that Adar * or Adar II. The birthday in an ordinary year of someone born during the * first 29 days of Adar I in a leap year is on the corresponding day of Adar; * in a leap year, the birthday occurs in Adar I, as expected. * * Someone born on the thirtieth day of Marcheshvan, Kislev, or Adar I * has his birthday postponed until the first of the following month in * years where that day does not occur. [Calendrical Calculations p. 111] * @example * import {getBirthdayOrAnniversary} from '@hebcal/hdate'; * const dt = new Date(2014, 2, 2); // '2014-03-02' == '30 Adar I 5774' * const anniversary = getBirthdayOrAnniversary(5780, dt); // '3/26/2020' == '1 Nisan 5780' * @param hyear Hebrew year * @param date Gregorian or Hebrew date of event * @returns anniversary occurring in `hyear` */ function getBirthdayOrAnniversary(hyear, date) { const hd = getBirthdayHD(hyear, date); if (typeof hd === 'undefined') { return hd; } return abs2greg(hebrew2abs(hd.yy, hd.mm, hd.dd)); } function getBirthdayHD(hyear, date) { const orig = toSimpleHebrewDate(date); const origYear = orig.yy; if (hyear === origYear) { return orig; } else if (hyear < origYear) { // Hebrew year ${hyear} occurs on or before original date in ${origYear} return undefined; } const isOrigLeap = isLeapYear(origYear); let month = orig.mm; let day = orig.dd; if ((month === ADAR_I && !isOrigLeap) || (month === ADAR_II && isOrigLeap)) { month = monthsInYear(hyear); } else if (month === CHESHVAN && day === 30 && !longCheshvan(hyear)) { month = KISLEV; day = 1; } else if (month === KISLEV && day === 30 && shortKislev(hyear)) { month = TEVET; day = 1; } else if (month === ADAR_I && day === 30 && isOrigLeap && !isLeapYear(hyear)) { month = NISAN; day = 1; } return { yy: hyear, mm: month, dd: day }; } export { getBirthdayHD, getBirthdayOrAnniversary, getYahrzeit, getYahrzeitHD }; //# sourceMappingURL=anniversary.js.map