@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
JavaScript
/*! @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