@hebcal/core
Version:
A perpetual Jewish Calendar API
1,628 lines (1,608 loc) • 480 kB
JavaScript
/*! @hebcal/core v5.10.1, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
var hebcal = (function (exports) {
'use strict';
/** DO NOT EDIT THIS AUTO-GENERATED FILE! */
const version = '5.10.1';
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
/* eslint-disable @typescript-eslint/no-namespace, no-inner-declarations */
/** @private */
const lengths = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
/** @private */
const monthLengths = [lengths, lengths.slice()];
monthLengths[1][2] = 29;
/**
* @private
*/
function mod$1(x, y) {
return x - y * Math.floor(x / y);
}
/**
* @private
*/
function quotient(x, y) {
return Math.floor(x / y);
}
/**
* @private
* @param abs - R.D. number of days
*/
function yearFromFixed(abs) {
const l0 = abs - 1;
const n400 = quotient(l0, 146097);
const d1 = mod$1(l0, 146097);
const n100 = quotient(d1, 36524);
const d2 = mod$1(d1, 36524);
const n4 = quotient(d2, 1461);
const d3 = mod$1(d2, 1461);
const n1 = quotient(d3, 365);
const year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
return n100 !== 4 && n1 !== 4 ? year + 1 : year;
}
/*
const ABS_14SEP1752 = 639797;
const ABS_2SEP1752 = 639785;
*/
/*
* Formerly in namespace, now top-level
*/
/**
* Returns true if the Gregorian year is a leap year
* @param year Gregorian year
*/
function isGregLeapYear(year) {
return !(year % 4) && (!!(year % 100) || !(year % 400));
}
/**
* Number of days in the Gregorian month for given year
* @param month Gregorian month (1=January, 12=December)
* @param year Gregorian year
*/
function daysInGregMonth(month, year) {
// 1 based months
return monthLengths[+isGregLeapYear(year)][month];
}
/**
* Returns true if the object is a Javascript Date
*/
function isDate(obj) {
// eslint-disable-next-line no-prototype-builtins
return typeof obj === 'object' && Date.prototype.isPrototypeOf(obj);
}
/**
* @private
* @param year
* @param month (1-12)
* @param day (1-31)
*/
function toFixed(year, month, day) {
const py = year - 1;
return 365 * py + quotient(py, 4) - quotient(py, 100) + quotient(py, 400) + quotient(367 * month - 362, 12) + (month <= 2 ? 0 : isGregLeapYear(year) ? -1 : -2) + day;
}
/**
* Converts Gregorian date to absolute R.D. (Rata Die) days
* @param date Gregorian date
*/
function greg2abs(date) {
if (!isDate(date)) {
throw new TypeError(`not a Date: ${date}`);
} else if (isNaN(date.getTime())) {
throw new RangeError('Invalid Date');
}
const abs = toFixed(date.getFullYear(), date.getMonth() + 1, date.getDate());
/*
if (abs < ABS_14SEP1752 && abs > ABS_2SEP1752) {
throw new RangeError(`Invalid Date: ${date}`);
}
*/
return abs;
}
/**
* Converts from Rata Die (R.D. number) to Gregorian date.
* See the footnote on page 384 of ``Calendrical Calculations, Part II:
* Three Historical Calendars'' by E. M. Reingold, N. Dershowitz, and S. M.
* Clamen, Software--Practice and Experience, Volume 23, Number 4
* (April, 1993), pages 383-404 for an explanation.
*
* Note that this function returns the daytime portion of the date.
* For example, the 15th of Cheshvan 5769 began at sundown on
* 12 November 2008 and continues through 13 November 2008. This
* function would return only the date 13 November 2008.
* @param abs - R.D. number of days
* @example
* const abs = hebrew2abs(5769, months.CHESHVAN, 15);
* const date = abs2greg(abs); // 13 November 2008
* const year = date.getFullYear(); // 2008
* const monthNum = date.getMonth() + 1; // 11
* const day = date.getDate(); // 13
*/
function abs2greg(abs) {
if (typeof abs !== 'number' || isNaN(abs)) {
throw new TypeError(`not a Number: ${abs}`);
}
abs = Math.trunc(abs);
/*
if (abs < ABS_14SEP1752 && abs > ABS_2SEP1752) {
throw new RangeError(`Invalid Date: ${abs}`);
}
*/
const year = yearFromFixed(abs);
const priorDays = abs - toFixed(year, 1, 1);
const correction = abs < toFixed(year, 3, 1) ? 0 : isGregLeapYear(year) ? 1 : 2;
const month = quotient(12 * (priorDays + correction) + 373, 367);
const day = abs - toFixed(year, month, 1) + 1;
const dt = new Date(year, month - 1, day);
if (year < 100 && year >= 0) {
dt.setFullYear(year);
}
return dt;
}
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-namespace */
/**
* Gregorian date helper functions
*/
exports.greg = void 0;
(function (greg) {})(exports.greg || (exports.greg = {}));
exports.greg.abs2greg = abs2greg;
exports.greg.daysInMonth = daysInGregMonth;
exports.greg.greg2abs = greg2abs;
exports.greg.isDate = isDate;
exports.greg.isLeapYear = isGregLeapYear;
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
/*
* More minimal HDate
*/
const NISAN$4 = 1;
const IYYAR$1 = 2;
const SIVAN$1 = 3;
const TAMUZ$1 = 4;
const AV$1 = 5;
const ELUL$1 = 6;
const TISHREI$2 = 7;
const CHESHVAN$1 = 8;
const KISLEV$2 = 9;
const TEVET$2 = 10;
const SHVAT$1 = 11;
const ADAR_I$2 = 12;
const ADAR_II$2 = 13;
/**
* Hebrew months of the year (NISAN=1, TISHREI=7)
* @readonly
* @enum {number}
*/
const months = {
/** Nissan / ניסן */
NISAN: NISAN$4,
/** Iyyar / אייר */
IYYAR: IYYAR$1,
/** Sivan / סיון */
SIVAN: SIVAN$1,
/** Tamuz (sometimes Tammuz) / תמוז */
TAMUZ: TAMUZ$1,
/** Av / אב */
AV: AV$1,
/** Elul / אלול */
ELUL: ELUL$1,
/** Tishrei / תִּשְׁרֵי */
TISHREI: TISHREI$2,
/** Cheshvan / חשון */
CHESHVAN: CHESHVAN$1,
/** Kislev / כסלו */
KISLEV: KISLEV$2,
/** Tevet / טבת */
TEVET: TEVET$2,
/** Sh'vat / שבט */
SHVAT: SHVAT$1,
/** Adar or Adar Rishon / אדר */
ADAR_I: ADAR_I$2,
/** Adar Sheini (only on leap years) / אדר ב׳ */
ADAR_II: ADAR_II$2
};
const NISAN_STR = 'Nisan';
const monthNames0 = ['', NISAN_STR, 'Iyyar', 'Sivan', 'Tamuz', 'Av', 'Elul', 'Tishrei', 'Cheshvan', 'Kislev', 'Tevet', "Sh'vat"];
/*
* Transliterations of Hebrew month names.
* Regular years are index 0 and leap years are index 1.
* @private
*/
const monthNames = [[...monthNames0, 'Adar', NISAN_STR], [...monthNames0, 'Adar I', 'Adar II', NISAN_STR]];
const edCache = new Map();
const EPOCH = -1373428;
// Avg year length in the cycle (19 solar years with 235 lunar months)
const AVG_HEBYEAR_DAYS = 365.24682220597794;
/**
* @private
*/
function assertNumber(n, name) {
if (typeof n !== 'number' || isNaN(n)) {
throw new TypeError(`param '${name}' not a number: ${n}`);
}
}
/**
* Converts Hebrew date to R.D. (Rata Die) fixed days.
* R.D. 1 is the imaginary date Monday, January 1, 1 on the Gregorian
* Calendar.
* @param year Hebrew year
* @param month Hebrew month
* @param day Hebrew date (1-30)
* @example
* const abs = hebrew2abs(5769, months.CHESHVAN, 15);
*/
function hebrew2abs(year, month, day) {
assertNumber(year, 'year');
assertNumber(month, 'month');
assertNumber(day, 'day');
if (year < 1) {
throw new RangeError(`hebrew2abs: invalid year ${year}`);
}
let tempabs = day;
if (month < TISHREI$2) {
for (let m = TISHREI$2; m <= monthsInYear(year); m++) {
tempabs += daysInMonth(m, year);
}
for (let m = NISAN$4; m < month; m++) {
tempabs += daysInMonth(m, year);
}
} else {
for (let m = TISHREI$2; m < month; m++) {
tempabs += daysInMonth(m, year);
}
}
return EPOCH + elapsedDays(year) + tempabs - 1;
}
/**
* @private
*/
function newYear(year) {
return EPOCH + elapsedDays(year);
}
/**
* Converts absolute R.D. days to Hebrew date
* @param abs absolute R.D. days
*/
function abs2hebrew(abs) {
assertNumber(abs, 'abs');
abs = Math.trunc(abs);
if (abs <= EPOCH) {
throw new RangeError(`abs2hebrew: ${abs} is before epoch`);
}
// first, quickly approximate year
let year = Math.floor((abs - EPOCH) / AVG_HEBYEAR_DAYS);
while (newYear(year) <= abs) {
++year;
}
--year;
let month = abs < hebrew2abs(year, 1, 1) ? 7 : 1;
while (abs > hebrew2abs(year, month, daysInMonth(month, year))) {
++month;
}
const day = 1 + abs - hebrew2abs(year, month, 1);
return {
yy: year,
mm: month,
dd: day
};
}
/**
* Returns true if Hebrew year is a leap year
* @param year Hebrew year
*/
function isLeapYear(year) {
return (1 + year * 7) % 19 < 7;
}
/**
* Number of months in this Hebrew year (either 12 or 13 depending on leap year)
* @param year Hebrew year
*/
function monthsInYear(year) {
return 12 + +isLeapYear(year); // boolean is cast to 1 or 0
}
/**
* Number of days in Hebrew month in a given year (29 or 30)
* @param month Hebrew month (e.g. months.TISHREI)
* @param year Hebrew year
*/
function daysInMonth(month, year) {
switch (month) {
case IYYAR$1:
case TAMUZ$1:
case ELUL$1:
case TEVET$2:
case ADAR_II$2:
return 29;
}
if (month === ADAR_I$2 && !isLeapYear(year) || month === CHESHVAN$1 && !longCheshvan(year) || month === KISLEV$2 && shortKislev(year)) {
return 29;
} else {
return 30;
}
}
/**
* Returns a transliterated string name of Hebrew month in year,
* for example 'Elul' or 'Cheshvan'.
* @param month Hebrew month (e.g. months.TISHREI)
* @param year Hebrew year
*/
function getMonthName(month, year) {
assertNumber(month, 'month');
assertNumber(year, 'year');
if (month < 1 || month > 14) {
throw new TypeError(`bad monthNum: ${month}`);
}
return monthNames[+isLeapYear(year)][month];
}
/**
* Days from sunday prior to start of Hebrew calendar to mean
* conjunction of Tishrei in Hebrew YEAR
* @param year Hebrew year
*/
function elapsedDays(year) {
const n = edCache.get(year);
if (typeof n === 'number') {
return n;
}
const elapsed = elapsedDays0(year);
edCache.set(year, elapsed);
return elapsed;
}
/**
* Days from sunday prior to start of Hebrew calendar to mean
* conjunction of Tishrei in Hebrew YEAR
* @private
* @param year Hebrew year
*/
function elapsedDays0(year) {
const prevYear = year - 1;
const mElapsed = 235 * Math.floor(prevYear / 19) +
// Months in complete 19 year lunar (Metonic) cycles so far
12 * (prevYear % 19) +
// Regular months in this cycle
Math.floor((prevYear % 19 * 7 + 1) / 19); // Leap months this cycle
const pElapsed = 204 + 793 * (mElapsed % 1080);
const hElapsed = 5 + 12 * mElapsed + 793 * Math.floor(mElapsed / 1080) + Math.floor(pElapsed / 1080);
const parts = pElapsed % 1080 + 1080 * (hElapsed % 24);
const day = 1 + 29 * mElapsed + Math.floor(hElapsed / 24);
let altDay = day;
if (parts >= 19440 || 2 === day % 7 && parts >= 9924 && !isLeapYear(year) || 1 === day % 7 && parts >= 16789 && isLeapYear(prevYear)) {
altDay++;
}
if (altDay % 7 === 0 || altDay % 7 === 3 || altDay % 7 === 5) {
return altDay + 1;
} else {
return altDay;
}
}
/**
* Number of days in the hebrew YEAR.
* A common Hebrew calendar year can have a length of 353, 354 or 355 days
* A leap Hebrew calendar year can have a length of 383, 384 or 385 days
* @param year Hebrew year
*/
function daysInYear(year) {
return elapsedDays(year + 1) - elapsedDays(year);
}
/**
* true if Cheshvan is long in Hebrew year
* @param year Hebrew year
*/
function longCheshvan(year) {
return daysInYear(year) % 10 === 5;
}
/**
* true if Kislev is short in Hebrew year
* @param year Hebrew year
*/
function shortKislev(year) {
return daysInYear(year) % 10 === 3;
}
/**
* Converts Hebrew month string name to numeric
* @param monthName monthName
*/
function monthFromName(monthName) {
if (typeof monthName === 'number') {
if (isNaN(monthName) || monthName < 1 || monthName > 14) {
throw new RangeError(`bad monthName: ${monthName}`);
}
return monthName;
}
let c = monthName.trim().toLowerCase();
// If Hebrew month starts with a bet (for example `בתמוז`) then ignore it
if (c[0] === 'ב') {
c = c.substring(1);
}
/*
the Hebrew months are unique to their second letter
N Nisan (November?)
I Iyyar
E Elul
C Cheshvan
K Kislev
1 1Adar
2 2Adar
Si Sh Sivan, Shvat
Ta Ti Te Tamuz, Tishrei, Tevet
Av Ad Av, Adar
אב אד אי אל אב אדר אייר אלול
ח חשון
ט טבת
כ כסלו
נ ניסן
ס סיון
ש שבט
תמ תש תמוז תשרי
*/
switch (c[0]) {
case 'n':
case 'נ':
if (c[1] === 'o') {
break; /* this catches "november" */
}
return NISAN$4;
case 'i':
return IYYAR$1;
case 'e':
return ELUL$1;
case 'c':
case 'ח':
return CHESHVAN$1;
case 'k':
case 'כ':
return KISLEV$2;
case 's':
switch (c[1]) {
case 'i':
return SIVAN$1;
case 'h':
return SHVAT$1;
}
break;
case 't':
switch (c[1]) {
case 'a':
return TAMUZ$1;
case 'i':
return TISHREI$2;
case 'e':
return TEVET$2;
}
break;
case 'a':
switch (c[1]) {
case 'v':
return AV$1;
case 'd':
if (/(1|[^i]i|a|א)$/i.test(monthName)) {
return ADAR_I$2;
}
return ADAR_II$2;
// else assume sheini
}
break;
case 'ס':
return SIVAN$1;
case 'ט':
return TEVET$2;
case 'ש':
return SHVAT$1;
case 'א':
switch (c[1]) {
case 'ב':
return AV$1;
case 'ד':
if (/(1|[^i]i|a|א)$/i.test(monthName)) {
return ADAR_I$2;
}
return ADAR_II$2;
// else assume sheini
case 'י':
return IYYAR$1;
case 'ל':
return ELUL$1;
}
break;
case 'ת':
switch (c[1]) {
case 'מ':
return TAMUZ$1;
case 'ש':
return TISHREI$2;
}
break;
}
throw new RangeError(`bad monthName: ${monthName}`);
}
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
const NISAN$3 = months.NISAN;
const CHESHVAN = months.CHESHVAN;
const KISLEV$1 = months.KISLEV;
const TEVET$1 = months.TEVET;
const SHVAT = months.SHVAT;
const ADAR_I$1 = months.ADAR_I;
const ADAR_II$1 = months.ADAR_II;
/**
* Returns true if the object is a SimpleHebrewDate
* @private
*/
function isSimpleHebrewDate$1(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$1(obj)) {
return obj;
} else if (isDate(obj)) {
const abs = greg2abs(obj);
return abs2hebrew(abs);
} else {
// typeof obj === 'number'
return abs2hebrew(obj);
}
}
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) - 1);
} else if (hDeath.mm === KISLEV$1 && 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) - 1);
} else if (hDeath.mm === ADAR_II$1) {
// 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$1 && 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$1;
hDeath.dd = 1;
} else if (hDeath.mm === KISLEV$1 && hDeath.dd === 30 && shortKislev(hyear)) {
hDeath.mm = TEVET$1;
hDeath.dd = 1;
}
hDeath.yy = hyear;
return hDeath;
}
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$1 && !isOrigLeap || month === ADAR_II$1 && isOrigLeap) {
month = monthsInYear(hyear);
} else if (month === CHESHVAN && day === 30 && !longCheshvan(hyear)) {
month = KISLEV$1;
day = 1;
} else if (month === KISLEV$1 && day === 30 && shortKislev(hyear)) {
month = TEVET$1;
day = 1;
} else if (month === ADAR_I$1 && day === 30 && isOrigLeap && !isLeapYear(hyear)) {
month = NISAN$3;
day = 1;
}
return {
yy: hyear,
mm: month,
dd: day
};
}
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
const GERESH = '׳';
const GERSHAYIM = '״';
const heb2num = {
א: 1,
ב: 2,
ג: 3,
ד: 4,
ה: 5,
ו: 6,
ז: 7,
ח: 8,
ט: 9,
י: 10,
כ: 20,
ל: 30,
מ: 40,
נ: 50,
ס: 60,
ע: 70,
פ: 80,
צ: 90,
ק: 100,
ר: 200,
ש: 300,
ת: 400
};
const num2heb = {};
for (const [key, val] of Object.entries(heb2num)) {
num2heb[val] = key;
}
function num2digits(num) {
const digits = [];
while (num > 0) {
if (num === 15 || num === 16) {
digits.push(9);
digits.push(num - 9);
break;
}
let incr = 100;
let i;
for (i = 400; i > num; i -= incr) {
if (i === incr) {
incr = incr / 10;
}
}
digits.push(i);
num -= i;
}
return digits;
}
/**
* Converts a numerical value to a string of Hebrew letters.
*
* When specifying years of the Hebrew calendar in the present millennium,
* we omit the thousands (which is presently 5 [ה]).
* @example
* gematriya(5774) // 'תשע״ד' - cropped to 774
* gematriya(25) // 'כ״ה'
* gematriya(60) // 'ס׳'
* gematriya(3761) // 'ג׳תשס״א'
* gematriya(1123) // 'א׳קכ״ג'
*/
function gematriya(num) {
const num1 = parseInt(num, 10);
if (!num1 || num1 < 0) {
throw new TypeError(`invalid number: ${num}`);
}
let str = '';
const thousands = Math.floor(num1 / 1000);
if (thousands > 0 && thousands !== 5) {
const tdigits = num2digits(thousands);
for (const tdig of tdigits) {
str += num2heb[tdig];
}
str += GERESH;
}
const digits = num2digits(num1 % 1000);
if (digits.length === 1) {
return str + num2heb[digits[0]] + GERESH;
}
for (let i = 0; i < digits.length; i++) {
if (i + 1 === digits.length) {
str += GERSHAYIM;
}
str += num2heb[digits[i]];
}
return str;
}
/**
* Converts a string of Hebrew letters to a numerical value.
*
* Only considers the value of Hebrew letters `א` through `ת`.
* Ignores final Hebrew letters such as `ך` (kaf sofit) or `ם` (mem sofit)
* and vowels (nekudot).
*/
function gematriyaStrToNum(str) {
let num = 0;
const gereshIdx = str.indexOf(GERESH);
if (gereshIdx !== -1 && gereshIdx !== str.length - 1) {
const thousands = str.substring(0, gereshIdx);
num += gematriyaStrToNum(thousands) * 1000;
str = str.substring(gereshIdx);
}
for (const ch of str) {
const n = heb2num[ch];
if (typeof n === 'number') {
num += n;
}
}
return num;
}
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
/**
* Calculates the molad for a Hebrew month
*/
function molad(year, month) {
let m_adj = month - 7;
if (m_adj < 0) {
m_adj += monthsInYear(year);
}
const mElapsed = 235 * Math.floor((year - 1) / 19) +
// Months in complete 19 year lunar (Metonic) cycles so far
12 * ((year - 1) % 19) +
// Regular months in this cycle
Math.floor((7 * ((year - 1) % 19) + 1) / 19) +
// Leap months this cycle
m_adj; // add elapsed months till the start of the molad of the month
const pElapsed = 204 + Math.floor(793 * (mElapsed % 1080));
const hElapsed = 5 + 12 * mElapsed + 793 * Math.floor(mElapsed / 1080) + Math.floor(pElapsed / 1080) - 6;
const parts = pElapsed % 1080 + 1080 * (hElapsed % 24);
const chalakim = parts % 1080;
const day = 1 + 29 * mElapsed + Math.floor(hElapsed / 24);
return {
year,
month,
dayOfWeek: day % 7,
hour: hElapsed % 24,
minutes: Math.floor(chalakim / 18),
chalakim: chalakim % 18
};
}
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
/**
* Formats a number with leading zeros so the resulting string is 4 digits long.
* Similar to `string.padStart(4, '0')` but will also format
* negative numbers similar to how the JavaScript date formats
* negative year numbers (e.g. `-37` is formatted as `-000037`).
*/
function pad4(num) {
if (num < 0) {
return '-00' + pad4(-num);
} else if (num < 10) {
return '000' + num;
} else if (num < 100) {
return '00' + num;
} else if (num < 1000) {
return '0' + num;
}
return String(num);
}
/**
* Formats a number with leading zeros so the resulting string is 2 digits long.
* Similar to `string.padStart(2, '0')`.
*/
function pad2(num) {
if (num >= 0 && num < 10) {
return '0' + num;
}
return String(num);
}
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
const _formatters = new Map();
/**
* @private
*/
function getFormatter$1(tzid) {
const fmt = _formatters.get(tzid);
if (fmt) return fmt;
const f = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
timeZone: tzid
});
_formatters.set(tzid, f);
return f;
}
const dateFormatRegex = /^(\d+).(\d+).(\d+),?\s+(\d+).(\d+).(\d+)/;
/**
* Returns a string similar to `Date.toISOString()` but in the
* timezone `tzid`. Contrary to the typical meaning of `Z` at the end
* of the string, this is not actually a UTC date.
*/
function getPseudoISO(tzid, date) {
const str = getFormatter$1(tzid).format(date);
const m = dateFormatRegex.exec(str);
if (m === null) {
throw new Error(`Unable to parse formatted string: ${str}`);
}
let hour = m[4];
if (hour === '24') {
hour = '00';
}
m[3] = pad4(parseInt(m[3], 10));
return `${m[3]}-${m[1]}-${m[2]}T${hour}:${m[5]}:${m[6]}Z`;
}
/**
* Returns number of minutes `tzid` is offset from UTC on date `date`.
*/
function getTimezoneOffset(tzid, date) {
const utcStr = getPseudoISO('UTC', date);
const localStr = getPseudoISO(tzid, date);
const diffMs = new Date(utcStr).getTime() - new Date(localStr).getTime();
return Math.ceil(diffMs / 1000 / 60);
}
/**
* Returns YYYY-MM-DD in the local timezone
*/
function isoDateString(dt) {
return pad4(dt.getFullYear()) + '-' + pad2(dt.getMonth() + 1) + '-' + pad2(dt.getDate());
}
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
var poAshkenazi$1 = {
"headers": {
"plural-forms": "nplurals=2; plural=(n > 1);",
"language": "en_CA@ashkenazi"
},
"contexts": {
"": {
"Tevet": ["Teves"]
}
}
};
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
var poHe$1 = {
"headers": {
"plural-forms": "nplurals=2; plural=(n > 1);",
"language": "he"
},
"contexts": {
"": {
"Adar": ["אַדָר"],
"Adar I": ["אַדָר א׳"],
"Adar II": ["אַדָר ב׳"],
"Av": ["אָב"],
"Cheshvan": ["חֶשְׁוָן"],
"Elul": ["אֱלוּל"],
"Iyyar": ["אִיָיר"],
"Kislev": ["כִּסְלֵו"],
"Nisan": ["נִיסָן"],
"Sh'vat": ["שְׁבָט"],
"Sivan": ["סִיוָן"],
"Tamuz": ["תַּמּוּז"],
"Tevet": ["טֵבֵת"],
"Tishrei": ["תִּשְׁרֵי"]
}
}
};
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
const noopLocale = {
headers: {
'plural-forms': 'nplurals=2; plural=(n!=1);'
},
contexts: {
'': {}
}
};
const alias = {
h: 'he',
a: 'ashkenazi',
s: 'en',
'': 'en'
};
/** @private */
const locales = new Map();
/** @private */
let activeLocale;
/** @private */
let activeName;
/** @private */
function getEnOrdinal(n) {
const s = ['th', 'st', 'nd', 'rd'];
const v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
}
/** @private */
function checkLocale(locale) {
if (typeof locale !== 'string') {
throw new TypeError(`Invalid locale name: ${locale}`);
}
return locale.toLowerCase();
}
/** @private */
function getExistingLocale(locale) {
const locale1 = checkLocale(locale);
const loc = locales.get(locale1);
if (!loc) {
throw new RangeError(`Locale '${locale}' not found`);
}
return loc;
}
/**
* A locale in Hebcal is used for translations/transliterations of
* holidays. `@hebcal/hdate` supports four locales by default
* * `en` - default, Sephardic transliterations (e.g. "Shabbat")
* * `ashkenazi` - Ashkenazi transliterations (e.g. "Shabbos")
* * `he` - Hebrew (e.g. "שַׁבָּת")
* * `he-x-NoNikud` - Hebrew without nikud (e.g. "שבת")
*/
class Locale {
/**
* Returns translation only if `locale` offers a non-empty translation for `id`.
* Otherwise, returns `undefined`.
* @param id Message ID to translate
* @param [locale] Optional locale name (i.e: `'he'`, `'fr'`). Defaults to active locale.
*/
static lookupTranslation(id, locale) {
const loc = typeof locale === 'string' && locales.get(locale.toLowerCase()) || activeLocale;
const array = loc[id];
if ((array === null || array === void 0 ? void 0 : array.length) && array[0].length) {
return array[0];
}
return undefined;
}
/**
* By default, if no translation was found, returns `id`.
* @param id Message ID to translate
* @param [locale] Optional locale name (i.e: `'he'`, `'fr'`). Defaults to active locale.
*/
static gettext(id, locale) {
const text = this.lookupTranslation(id, locale);
if (typeof text === 'undefined') {
return id;
}
return text;
}
/**
* Register locale translations.
* @param locale Locale name (i.e.: `'he'`, `'fr'`)
* @param data parsed data from a `.po` file.
*/
static addLocale(locale, data) {
locale = checkLocale(locale);
if (typeof data.contexts !== 'object' || typeof data.contexts[''] !== 'object') {
throw new TypeError(`Locale '${locale}' invalid compact format`);
}
locales.set(locale, data.contexts['']);
}
/**
* Adds a translation to `locale`, replacing any previous translation.
* @param locale Locale name (i.e: `'he'`, `'fr'`).
* @param id Message ID to translate
* @param translation Translation text
*/
static addTranslation(locale, id, translation) {
const loc = getExistingLocale(locale);
if (typeof id !== 'string' || id.length === 0) {
throw new TypeError(`Invalid id string: ${id}`);
}
const isArray = Array.isArray(translation);
if (isArray) {
const t0 = translation[0];
if (typeof t0 !== 'string' || t0.length === 0) {
throw new TypeError(`Invalid translation array: ${translation}`);
}
} else if (typeof translation !== 'string') {
throw new TypeError(`Invalid translation string: ${translation}`);
}
loc[id] = isArray ? translation : [translation];
}
/**
* Adds multiple translations to `locale`, replacing any previous translations.
* @param locale Locale name (i.e: `'he'`, `'fr'`).
* @param data parsed data from a `.po` file.
*/
static addTranslations(locale, data) {
const loc = getExistingLocale(locale);
if (typeof data.contexts !== 'object' || typeof data.contexts[''] !== 'object') {
throw new TypeError(`Locale '${locale}' invalid compact format`);
}
const ctx = data.contexts[''];
Object.assign(loc, ctx);
}
/**
* Activates a locale. Throws an error if the locale has not been previously added.
* After setting the locale to be used, all strings marked for translations
* will be represented by the corresponding translation in the specified locale.
* @param locale Locale name (i.e: `'he'`, `'fr'`)
* @deprecated
*/
static useLocale(locale) {
const locale0 = checkLocale(locale);
const obj = getExistingLocale(locale0);
activeName = alias[locale0] || locale0;
activeLocale = obj;
return activeLocale;
}
/**
* Returns the name of the active locale (i.e. 'he', 'ashkenazi', 'fr')
* @deprecated
*/
static getLocaleName() {
return activeName;
}
/**
* Returns the names of registered locales
*/
static getLocaleNames() {
const keys = Array.from(locales.keys());
return keys.sort((a, b) => a.localeCompare(b));
}
/**
* Renders a number in ordinal, such as 1st, 2nd or 3rd
* @param [locale] Optional locale name (i.e: `'he'`, `'fr'`). Defaults to active locale.
*/
static ordinal(n, locale) {
const locale1 = locale === null || locale === void 0 ? void 0 : locale.toLowerCase();
const locale0 = locale1 || activeName;
if (!locale0) {
return getEnOrdinal(n);
}
switch (locale0) {
case 'en':
case 's':
case 'a':
return getEnOrdinal(n);
case 'es':
return n + 'º';
case 'h':
case 'he':
case 'he-x-nonikud':
return String(n);
}
if (locale0.startsWith('ashkenazi')) {
return getEnOrdinal(n);
}
return n + '.';
}
/**
* Removes nekudot from Hebrew string
*/
static hebrewStripNikkud(str) {
const a = str.normalize();
// now strip out niqqud and trope
return a.replace(/[\u0590-\u05bd]/g, '').replace(/[\u05bf-\u05c7]/g, '');
}
}
Locale.addLocale('en', noopLocale);
Locale.addLocale('s', noopLocale);
Locale.addLocale('', noopLocale);
Locale.useLocale('en');
/* Ashkenazic transliterations */
Locale.addLocale('ashkenazi', poAshkenazi$1);
Locale.addLocale('a', poAshkenazi$1);
/* Hebrew with nikkud */
Locale.addLocale('he', poHe$1);
Locale.addLocale('h', poHe$1);
/* Hebrew without nikkud */
const heStrs$1 = poHe$1.contexts[''];
const heNoNikud$1 = {};
for (const [key, val] of Object.entries(heStrs$1)) {
heNoNikud$1[key] = [Locale.hebrewStripNikkud(val[0])];
}
const poHeNoNikud$1 = {
headers: poHe$1.headers,
contexts: {
'': heNoNikud$1
}
};
Locale.addLocale('he-x-NoNikud', poHeNoNikud$1);
/*! @hebcal/hdate v0.14.2, distributed under GPLv2 https://www.gnu.org/licenses/gpl-2.0.txt */
/*
Hebcal - A Jewish Calendar Generator
Copyright (c) 1994-2020 Danny Sadinoff
Portions copyright Eyal Schachter and Michael J. Radwin
https://github.com/hebcal/hebcal-es6
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
function mod(x, y) {
return x - y * Math.floor(x / y);
}
function isSimpleHebrewDate(obj) {
return obj.yy !== undefined;
}
const UNITS_DAY = 'day';
const UNITS_WEEK = 'week';
const UNITS_MONTH = 'month';
const UNITS_YEAR = 'year';
/**
* A `HDate` represents a Hebrew calendar date.
*
* An instance of this class encapsulates a date in the Hebrew calendar system.
* It consists of a year, month, and day, without any associated time or location data.
* The Hebrew calendar is a lunisolar calendar, meaning it is based on both lunar and solar cycles.
*
* A Hebrew date internally stores three numbers:
* - year: The Hebrew year (1-9999). Counted from the traditional Hebrew date of creation (3761 BCE in the Gregorian calendar)
* - month: The Hebrew month (1-13). Month 1 is Nisan, month 7 is Tishrei. There are 12 months in a regular year and 13 months in a leap year.
* - day: The day of the month (1-30)
*
* This class uses Rata Die to convert between the Hebrew and Gregorian calendars.
*
* To calculate times of day, use `Zmanim` class from `@hebcal/core`
* @see {@link https://en.wikipedia.org/wiki/Rata_Die | Rata Die}
* @see {@link https://hebcal.github.io/api/core/classes/Zmanim.html | Zmanim}
*/
class HDate {
/**
* Create a Hebrew date. There are 3 basic forms for the `HDate()` constructor.
*
* 1. No parameters - represents the current Hebrew date at time of instantiation
* 2. One parameter
* * `Date` - represents the Hebrew date corresponding to the Gregorian date using
* local time. Hours, minutes, seconds and milliseconds are ignored.
* * `HDate` - clones a copy of the given Hebrew date
* * `number` - Converts absolute R.D. days to Hebrew date.
* R.D. 1 == the imaginary date January 1, 1 (Gregorian)
* 3. Three parameters: Hebrew day, Hebrew month, Hebrew year. Hebrew day should
* be a number between 1-30, Hebrew month can be a number or string, and
* Hebrew year is always a number.
* @example
* import {HDate, months} from '@hebcal/hdate';
*
* const hd1 = new HDate();
* const hd2 = new HDate(new Date(2008, 10, 13));
* const hd3 = new HDate(15, 'Cheshvan', 5769);
* const hd4 = new HDate(15, months.CHESHVAN, 5769);
* const hd5 = new HDate(733359); // ==> 15 Cheshvan 5769
* const monthName = 'אייר';
* const hd6 = new HDate(5, monthName, 5773);
* @param [day] - Day of month (1-30) if a `number`.
* If a `Date` is specified, represents the Hebrew date corresponding to the
* Gregorian date using local time.
* If an `HDate` is specified, clones a copy of the given Hebrew date.
* @param [month] - Hebrew month of year (1=NISAN, 7=TISHREI)
* @param [year] - Hebrew year
*/
constructor(day, month, year) {
if (arguments.length === 2 || arguments.length > 3) {
throw new TypeError('HDate constructor requires 0, 1 or 3 arguments');
}
if (arguments.length === 3) {
// Hebrew day, Hebrew month, Hebrew year
this.dd = this.mm = 1;
const yy = typeof year === 'string' ? parseInt(year, 10) : year;
if (isNaN(yy)) {
throw new TypeError(`HDate called with bad year: ${year}`);
}
this.yy = yy;
setMonth(this, month); // will throw if we can't parse
const dd = typeof day === 'string' ? parseInt(day, 10) : day;
if (isNaN(dd)) {
throw new TypeError(`HDate called with bad day: ${day}`);
}
setDate(this, dd);
} else {
// 0 arguments
if (typeof day === 'undefined' || day === null) {
day = new Date();
}
// 1 argument
const abs0 = typeof day === 'number' && !isNaN(day) ? day : isDate(day) ? greg2abs(day) : isSimpleHebrewDate(day) ? day : null;
if (abs0 === null) {
throw new TypeError(`HDate called with bad arg: ${day}`);
}
const isNumber = typeof abs0 === 'number';
const d = isNumber ? abs2hebrew(abs0) : abs0;
this.yy = d.yy;
this.mm = d.mm;
this.dd = d.dd;
if (isNumber) {
this.rd = abs0;
}
}
}
/**
* Returns the Hebrew year of this Hebrew date
* @returns an integer >= 1
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.getFullYear(); // 5769
*/
getFullYear() {
return this.yy;
}
/**
* Returns `true` if this Hebrew date occurs during a Hebrew leap year
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.isLeapYear(); // false
*/
isLeapYear() {
return isLeapYear(this.yy);
}
/**
* Returns the Hebrew month (1=NISAN, 7=TISHREI) of this Hebrew date
* @returns an integer 1-13
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.getMonth(); // 8
*/
getMonth() {
return this.mm;
}
/**
* The Tishrei-based month of this Hebrew date. 1 is Tishrei, 7 is Nisan, 13 is Elul in a leap year
* @returns an integer 1-13
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.getTishreiMonth(); // 2
*/
getTishreiMonth() {
const nummonths = monthsInYear(this.getFullYear());
return (this.getMonth() + nummonths - 6) % nummonths || nummonths;
}
/**
* Number of days in the month of this Hebrew date (29 or 30)
* @returns an integer 29-30
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.daysInMonth(); // 29
*/
daysInMonth() {
return daysInMonth(this.getMonth(), this.getFullYear());
}
/**
* Gets the day within the month (1-30)
* @returns an integer 1-30
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.getDate(); // 15
*/
getDate() {
return this.dd;
}
/**
* Returns the day of the week for this Hebrew date,
* where 0 represents Sunday, 1 represents Monday, 6 represents Saturday.
*
* For the day of the month, see `getDate()`
* @returns an integer 0-6
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.getDate(); // 4
*/
getDay() {
return mod(this.abs(), 7);
}
/**
* Converts this Hebrew date to the corresponding Gregorian date.
*
* The returned `Date` object will be in the local (i.e. host system) time zone.
* Hours, minutes, seconds and milliseconds will all be zero.
*
* Note that this function returns the daytime portion of the date.
* For example, the 15th of Cheshvan 5769 began at sundown on
* 12 November 2008 and continues through 13 November 2008. This
* function would return only the date 13 November 2008.
* @example
* const hd = new HDate(15, 'Cheshvan', 5769);
* const date = hd.greg(); // 13 November 2008
* const year = date.getFullYear(); // 2008
* const monthNum = date.getMonth() + 1; // 11
* const day = date.getDate(); // 13
*/
greg() {
return abs2greg(this.abs());
}
/**
* Converts from Hebrew date representation to R.D. (Rata Die) fixed days.
* R.D. 1 is the imaginary date Monday, January 1, 1 (Gregorian).
* Note also that R.D. = Julian Date − 1,721,424.5
* @see {@link https://en.wikipedia.org/wiki/Rata_Die | Rata Die}
* @example
* const hd = new HDate(15, 'Cheshvan', 5769);
* hd.abs(); // 733359
*/
abs() {
if (typeof this.rd !== 'number') {
this.rd = hebrew2abs(this.yy, this.mm, this.dd);
}
return this.rd;
}
/**
* Converts Hebrew date to R.D. (Rata Die) fixed days.
* R.D. 1 is the imaginary date Monday, January 1, 1 on the Gregorian
* Calendar.
* @param year Hebrew year
* @param month Hebrew month (1=NISAN, 7=TISHREI)
* @param day Hebrew date (1-30)
* @example
* import {HDate, months} from '@hebcal/hdate';
* HDate.hebrew2abs(5769, months.CHESHVAN, 15); // 733359
*/
static hebrew2abs(year, month, day) {
return hebrew2abs(year, month, day);
}
/**
* Returns a transliterated Hebrew month name, e.g. `'Elul'` or `'Cheshvan'`.
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.getMonthName(); // 'Cheshvan'
*/
getMonthName() {
return getMonthName(this.getMonth(), this.getFullYear());
}
/**
* Renders this Hebrew date as a translated or transliterated string,
* including ordinal e.g. `'15th of Cheshvan, 5769'`.
* @example
* import {HDate, months} from '@hebcal/hdate';
*
* const hd = new HDate(15, months.CHESHVAN, 5769);
* console.log(hd.render('en')); // '15th of Cheshvan, 5769'
* console.log(hd.render('he')); // '15 חֶשְׁוָן, 5769'
* console.log(hd.render('en', false)); // '15th of Cheshvan'
* console.log(hd.render('he', false)); // '15 חֶשְׁוָן'
* @param [locale] Optional locale name (defaults to active locale).
* @param [showYear=true] Display year (defaults to true).
* @see {@link Locale}
*/
render(locale) {
let showYear = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
const locale0 = locale || Locale.getLocaleName();
const day = this.getDate();
const monthName0 = Locale.gettext(this.getMonthName(), locale0);
const monthName = monthName0.replace(/'/g, '’');
const nth = Locale.ordinal(day, locale0);
const dayOf = getDayOfTranslation(locale0);
const dateStr = `${nth}${dayOf} ${monthName}`;
if (showYear) {
const fullYear = this.getFullYear();
return `${dateStr}, ${fullYear}`;
} else {
return dateStr;
}
}
/**
* Renders this Hebrew date in Hebrew gematriya, regardless of locale.
* @example
* import {HDate, months} from '@hebcal/hdate';
* const hd = new HDate(15, months.CHESHVAN, 5769);
* hd.renderGematriya(); // 'ט״ו חֶשְׁוָן תשס״ט'
* hd.renderGematriya(true); // 'ט״ו חשון תשס״ט'
*/
renderGematriya() {
let suppressNikud = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
const d = this.getDate();
const locale = suppressNikud ? 'he-x-NoNikud' : 'he';
const m = Locale.gettext(this.getMonthName(), locale);
const y = this.getFullYear();
return gematriya(d) + ' ' + m + ' ' + gematriya(y);
}
/**
* Returns an `HDate` corresponding to the specified day of week
* **before** this Hebrew date
* @example
* new HDate(new Date('Wednesday February 19, 2014')).before(6).greg() // Sat Feb 15 2014
* @param dayOfWeek day of week: Sunday=0, Saturday=6
*/
before(dayOfWeek) {
return onOrBefore(dayOfWeek, this, -1);
}
/**
* Returns an `HDate` corresponding to the specified day of week
* **on or before** this Hebrew date
* @example
* new HDate(new Date('Wednesday February 19, 2014')).onOrBefore(6).greg() // Sat Feb 15 2014
* new HDate(new Date('Saturday February 22, 2014')).onOrBefore(6).greg() // Sat Feb 22 2014
* new HDate(new Date('Sunday February 23, 2014')).onOrBefore(6).greg() // Sat Feb 22 2014
* @param dayOfWeek day of week: Sunday=0, Saturday=6
*/
onOrBefore(dayOfWeek) {
return onOrBefore(dayOfWeek, this, 0);
}
/**
* Returns an `HDate` corresponding to the specified day of week
* **nearest** to this Hebrew date
* @example
* new HDate(new Date('Wednesday February 19, 2014')).nearest(6).greg() // Sat Feb 22 2014
* new HDate(new Date('Tuesday February 18, 2014')).nearest(6).greg() // Sat Feb 15 2014
* @param dayOfWeek day of week: Sunday=0, Saturday=6
*/
nearest(dayOfWeek) {
return onOrBefore(dayOfWeek, this, 3);
}
/**
* Returns an `HDate` corresponding to the specified day of week
* **on or after** this Hebrew date
* @example
* new HDate(new Date('Wednesday February 19, 2014')).onOrAfter(6).greg() // Sat Feb 22 2014
* new HDate(new Date('Saturday February 22, 2014')).onOrAfter(6).greg() // Sat Feb 22 2014
* new HDate(new Date('Sunday February 23, 2014')).onOrAfter(6).greg() // Sat Mar 01 2014
* @param dayOfWeek day of week: Sunday=0, Saturday=6
*/
onOrAfter(dayOfWeek) {
return onOrBefore(dayOfWeek, this, 6);
}
/**
* Returns an `HDate` corresponding to the specified day of week
* **after** this Hebrew date
* @example
* new HDate(new Date('Wednesday February 19, 2014')).after(6).greg() // Sat Feb 22 2014
* new HDate(new Date('Saturday February 22, 2014')).after(6).greg() // Sat Mar 01 2014
* new HDate(new Date('Sunday February 23, 2014')).after(6).greg() // Sat Mar 01 2014
* @param dayOfWeek day of week: Sunday=0, Saturday=6
*/
after(dayOfWeek) {
return onOrBefore(dayOfWeek, this, 7);
}
/**
* Returns the next Hebrew date
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.next(); // '16 Cheshvan 5769'
*/
next() {
return new HDate(this.abs() + 1);
}
/**
* Returns the previous Hebrew date
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.prev(); // '14 Cheshvan 5769'
*/
prev() {
return new HDate(this.abs() - 1);
}
/**
* Returns a cloned `HDate` object with a specified amount of time added
*
* Units are case insensitive, and support plural and short forms.
* Note, short forms are case sensitive.
*
* | Unit | Shorthand | Description
* | --- | --- | --- |
* | `day` | `d` | days |
* | `week` | `w` | weeks |
* | `month` | `M` | months |
* | `year` | `y` | years |
*/
add(amount) {
let units = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'd';
amount = typeof amount === 'string' ? parseInt(amount, 10) : amount;
if (!amount) {
return new HDate(this);
}
units = standardizeUnits(units);
if (units === UNITS_DAY) {
return new HDate(this.abs() + amount);
} else if (units === UNITS_WEEK) {
return new HDate(this.abs() + 7 * amount);
} else if (units === UNITS_YEAR) {
return new HDate(this.getDate(), this.getMonth(), this.getFullYear() + amount);
} else {
// units === UNITS_MONTH
let hd = new HDate(this);
const sign = amount > 0 ? 1 : -1;
amount = Math.abs(amount);
for (let i = 0; i < amount; i++) {
hd = new HDate(hd.abs() + sign * hd.daysInMonth());
}
return hd;
}
}
/**
* Returns a cloned `HDate` object with a specified amount of time subracted
*
* Units are case insensitive, and support plural and short forms.
* Note, short forms are case sensitive.
*
* | Unit | Shorthand | Description
* | --- | --- | --- |
* | `day` | `d` | days |
* | `week` | `w` | weeks |
* | `month` | `M` | months |
* | `year` | `y` | years |
* @example
* import {HDate, months} from '@hebcal/hdate';
*
* const hd1 = new HDate(15, months.CHESHVAN, 5769);
* const hd2 = hd1.add(1, 'weeks'); // 7 Kislev 5769
* const hd3 = hd1.add(-3, 'M'); // 30 Av 5768
*/
subtract(amount) {
let units = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'd';
return this.add(amount * -1, units);
}
/**
* Returns the difference in days between the two given HDates.
*
* The result is positive if `this` date is comes chronologically
* after the `other` date, and negative
* if the order of the two dates is reversed.
*
* The result is zero if the two dates are identical.
* @example
* import {HDate, months} from '@hebcal/hdate';
*
* const hd1 = new HDate(25, months.KISLEV, 5770);
* const hd2 = new HDate(15, months.CHESHVAN, 5769);
* const days = hd1.deltaDays(hd2); // 394
* @param other Hebrew date to compare
*/
deltaDays(other) {
return this.abs() - other.abs();
}
/**
* Compares this Hebrew date to another date, returning `true` if the dates match.
* @param other Hebrew date to compare
* @example
* const hd1 = new HDate(new Date(2008, 10, 13));
* const hd2 = new HDate(15, 'Cheshvan', 5769);
* hd1.isSameDate(hd2); // true
*/
isSameDate(other) {
return this.yy === other.yy && this.mm === other.mm && this.dd === other.dd;
}
/**
* Returns a string representation of this Hebrew date using English transliterations
* @example
* const hd = new HDate(new Date(2008, 10, 13)); // 15 Cheshvan 5769
* hd.toString(); // '15 Cheshvan 5769'
*/
toString() {
const day = this.getDate();
const fullYear = this.getFullYear();
const monthName = this.getMonthName();
return `${day} ${monthName} ${fullYear}`;
}
/**
* Returns true if Hebrew year is a leap year
* @param year Hebrew year
* @example
* HDate.isLeapYear(5783); // false
* HDate.isLeapYear(5784); // true
*/
static isLeapYear(year) {
return isLeapYear(year);
}
/**
* Number of months in this Hebrew year (either 12 or 13 depending on leap year)
* @param year Hebrew year
* @example
* HDate.monthsInYear(5783); // 12
* HDate.monthsInYear(5784); // 13
*/
static monthsInYear(year) {
return monthsInYear(year);
}
/**
* Number of days in Hebrew month in a given year (29 or 30)
* @param month Hebrew month (e.g. months.TISHREI)
* @param year Hebrew year
* @example
* import {HDate, months} from '@hebcal/hdate';
* HDate.daysInMonth(months.CHESHVAN, 5769); // 29
*/
static daysInMonth(month, year) {
return daysInMonth(month, year);
}
/**
* Returns a transliterated string name of Hebrew month in year,
* for example 'Elul' or 'Cheshvan'.
* @param month Hebrew month (e.g. months.TISHREI)
* @param year Hebrew year
* @example
* import {HDate, months} from '@hebcal/hdate';
* HDate.getMonthName(months.CHESHVAN, 5769); // 'Cheshvan'
*/
static getMonthName(month, year) {
return getMonthName(month, year);
}
/**
* Returns the Hebrew month number (NISAN=1, TISHREI=7)
* @param month A number, or Hebrew month name string
* @example
* import {HDate, months} from '@hebcal/hdate';
* HDate.monthNum(months.CHESHVAN); // 8
* HDate.monthNum('Cheshvan'); // 8
* HDate.monthNum('חשון'); // 8
*/
static monthNum(month) {
if (typeof month === 'number') {
if (isNaN(month) || month > 14) {
throw new RangeError(`bad monthNum: ${month