Skip to content

Commit

Permalink
Export getHolidaysOnDate as a function outside of HebrewCalendar wrap…
Browse files Browse the repository at this point in the history
…per class #475
  • Loading branch information
mjradwin committed Nov 3, 2024
1 parent 4ea4b83 commit 40a065a
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 81 deletions.
55 changes: 10 additions & 45 deletions src/hebcal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ import {TimedEvent, HavdalahEvent} from './TimedEvent';
import {Event, flags} from './event';
import {Sedra, getSedra_} from './sedra';
import {hallel_} from './hallel';
import {getHolidaysForYear_, HolidayYearMap} from './holidays';
import {
getHolidaysForYear_,
getHolidaysForYearArray,
getHolidaysOnDate,
HolidayYearMap,
} from './holidays';
import {MevarchimChodeshEvent} from './MevarchimChodeshEvent';
import {HolidayEvent} from './HolidayEvent';
import {Location} from './location';
Expand Down Expand Up @@ -351,20 +356,6 @@ function setOptionsFromMask(options: CalOptions): number {
return m;
}

/**
* @private
*/
function observedInIsrael(ev: Event): boolean {
return ev.observedInIsrael();
}

/**
* @private
*/
function observedInDiaspora(ev: Event): boolean {
return ev.observedInDiaspora();
}

/**
* HebrewCalendar is the main interface to the `@hebcal/core` library.
* This namespace is used to calculate holidays, rosh chodesh, candle lighting & havdalah times,
Expand Down Expand Up @@ -703,20 +694,7 @@ export class HebrewCalendar {
* @param il use the Israeli schedule for holidays
*/
static getHolidaysForYearArray(year: number, il: boolean): HolidayEvent[] {
const yearMap = getHolidaysForYear_(year);
const startAbs = HDate.hebrew2abs(year, TISHREI, 1);
const endAbs = HDate.hebrew2abs(year + 1, TISHREI, 1) - 1;
let events: HolidayEvent[] = [];
const myFilter = il ? observedInIsrael : observedInDiaspora;
for (let absDt = startAbs; absDt <= endAbs; absDt++) {
const hd = new HDate(absDt);
const holidays = yearMap.get(hd.toString());
if (holidays) {
const filtered: HolidayEvent[] = holidays.filter(myFilter);
events = events.concat(filtered);
}
}
return events;
return getHolidaysForYearArray(year, il);
}

/**
Expand All @@ -728,17 +706,7 @@ export class HebrewCalendar {
date: HDate | Date | number,
il?: boolean
): HolidayEvent[] | undefined {
const hd = HDate.isHDate(date) ? (date as HDate) : new HDate(date);
const hdStr = hd.toString();
const yearMap = getHolidaysForYear_(hd.getFullYear());
const events = yearMap.get(hdStr);
// if il isn't a boolean return both diaspora + IL for day
if (typeof il === 'undefined' || typeof events === 'undefined') {
return events;
}
const myFilter = il ? observedInIsrael : observedInDiaspora;
const filtered = events.filter(myFilter);
return filtered;
return getHolidaysOnDate(date, il);
}

/**
Expand Down Expand Up @@ -802,10 +770,7 @@ export class HebrewCalendar {
* 2 - Whole Hallel
*/
static hallel(hdate: HDate, il: boolean): number {
const events = HebrewCalendar.getHolidaysForYearArray(
hdate.getFullYear(),
il
);
const events = getHolidaysForYearArray(hdate.getFullYear(), il);
return hallel_(events, hdate);
}

Expand Down Expand Up @@ -834,7 +799,7 @@ export class HebrewCalendar {
* @private
*/
function isChag(date: HDate, il: boolean): boolean {
const events = HebrewCalendar.getHolidaysOnDate(date, il) || [];
const events = getHolidaysOnDate(date, il) || [];
const chag = events.filter(ev => ev.getFlags() & flags.CHAG);
return chag.length !== 0;
}
Expand Down
55 changes: 55 additions & 0 deletions src/holidays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,3 +425,58 @@ function getBirkatHaChama(year: number): number {
}
return 0;
}

function observedInIsrael(ev: HolidayEvent): boolean {
return ev.observedInIsrael();
}

function observedInDiaspora(ev: HolidayEvent): boolean {
return ev.observedInDiaspora();
}

/**
* Returns an array of Events on this date (or `undefined` if no events)
* @param date Hebrew Date, Gregorian date, or absolute R.D. day number
* @param [il] use the Israeli schedule for holidays
*/
export function getHolidaysOnDate(
date: HDate | Date | number,
il?: boolean
): HolidayEvent[] | undefined {
const hd = HDate.isHDate(date) ? (date as HDate) : new HDate(date);
const hdStr = hd.toString();
const yearMap = getHolidaysForYear_(hd.getFullYear());
const events = yearMap.get(hdStr);
// if il isn't a boolean return both diaspora + IL for day
if (typeof il === 'undefined' || typeof events === 'undefined') {
return events;
}
const myFilter = il ? observedInIsrael : observedInDiaspora;
const filtered = events.filter(myFilter);
return filtered;
}

/**
* Returns an array of holidays for the year
* @param year Hebrew year
* @param il use the Israeli schedule for holidays
*/
export function getHolidaysForYearArray(
year: number,
il: boolean
): HolidayEvent[] {
const yearMap = getHolidaysForYear_(year);
const startAbs = HDate.hebrew2abs(year, TISHREI, 1);
const endAbs = HDate.hebrew2abs(year + 1, TISHREI, 1) - 1;
let events: HolidayEvent[] = [];
const myFilter = il ? observedInIsrael : observedInDiaspora;
for (let absDt = startAbs; absDt <= endAbs; absDt++) {
const hd = new HDate(absDt);
const holidays = yearMap.get(hd.toString());
if (holidays) {
const filtered: HolidayEvent[] = holidays.filter(myFilter);
events = events.concat(filtered);
}
}
return events;
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export {
RoshChodeshEvent,
RoshHashanaEvent,
} from './HolidayEvent';
export {HolidayYearMap} from './holidays';
export {HolidayYearMap, getHolidaysOnDate} from './holidays';
export {MevarchimChodeshEvent} from './MevarchimChodeshEvent';
export {holidayDesc} from './staticHolidays';
export {DailyLearning} from './DailyLearning';
Expand Down
26 changes: 17 additions & 9 deletions test/getHolidaysForYear.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import {HebrewCalendar} from '../src/hebcal';
import {
getHolidaysForYear_,
getHolidaysForYearArray,
} from '../src/holidays';
import {isoDateString} from '@hebcal/hdate';

jest.mock('quick-lru', () => {
Expand All @@ -14,7 +17,7 @@ function eventDateDesc(ev) {
}

test('getHolidaysForYearArray-5771-diaspora', () => {
const events = HebrewCalendar.getHolidaysForYearArray(5771, false).map(eventDateDesc);
const events = getHolidaysForYearArray(5771, false).map(eventDateDesc);
const expected = [
{date: '2010-09-09', desc: 'Rosh Hashana 5771'},
{date: '2010-09-10', desc: 'Rosh Hashana II'},
Expand Down Expand Up @@ -119,7 +122,7 @@ test('getHolidaysForYearArray-5771-diaspora', () => {
});

test('getHolidaysForYearArray-5720-il', () => {
const events = HebrewCalendar.getHolidaysForYearArray(5720, true).map(eventDateDesc);
const events = getHolidaysForYearArray(5720, true).map(eventDateDesc);
const expected = [
{date: '1959-10-03', desc: 'Rosh Hashana 5720'},
{date: '1959-10-04', desc: 'Rosh Hashana II'},
Expand Down Expand Up @@ -214,23 +217,23 @@ test('getHolidaysForYearArray-5720-il', () => {
});

test('getHolidaysForYear-ce', () => {
const map = HebrewCalendar.getHolidaysForYear(5888);
const map = getHolidaysForYear_(5888);
const rh = map.get('1 Tishrei 5888').map(eventDateDesc)[0];
const pesach = map.get('15 Nisan 5888').map(eventDateDesc)[0];
expect(rh).toEqual({date: '2127-09-08', desc: 'Rosh Hashana 5888'});
expect(pesach).toEqual({date: '2128-04-15', desc: 'Pesach I'});
});

test('getHolidaysForYear-bce', () => {
const map = HebrewCalendar.getHolidaysForYear(3737);
const map = getHolidaysForYear_(3737);
const rh = map.get('1 Tishrei 3737').map(eventDateDesc)[0];
const pesach = map.get('15 Nisan 3737').map(eventDateDesc)[0];
expect(rh).toEqual({date: '-000024-09-11', desc: 'Rosh Hashana 3737'});
expect(pesach).toEqual({date: '-000023-03-22', desc: 'Pesach I'});
});

test('getHolidaysForYearArray-bce', () => {
const events = HebrewCalendar.getHolidaysForYearArray(3759, false).slice(0, 15);
const events = getHolidaysForYearArray(3759, false).slice(0, 15);
const actual = events.map(eventDateDesc);
const expected = [
{date: '-000002-09-08', desc: 'Rosh Hashana 3759'},
Expand All @@ -255,7 +258,7 @@ test('getHolidaysForYearArray-bce', () => {
test('Birkat Hachamah', () => {
const actual = [];
for (let year = 5650; year <= 5920; year++) {
const events = HebrewCalendar.getHolidaysForYearArray(year, false);
const events = getHolidaysForYearArray(year, false);
const ev = events.find((ev) => ev.getDesc() === 'Birkat Hachamah');
if (ev) {
actual.push(year);
Expand All @@ -264,14 +267,19 @@ test('Birkat Hachamah', () => {
const expected = [5657, 5685, 5713, 5741, 5769, 5797, 5825, 5853, 5881, 5909];
expect(actual).toEqual(expected);

const events = HebrewCalendar.getHolidaysForYearArray(5965, false);
const events = getHolidaysForYearArray(5965, false);
const ev = events.find((ev) => ev.getDesc() === 'Birkat Hachamah');
expect(typeof ev).toBe('object');
expect(ev.getDate().toString()).toBe('19 Nisan 5965');

const events2 = HebrewCalendar.getHolidaysForYearArray(5993, false);
const events2 = getHolidaysForYearArray(5993, false);
const ev2 = events2.find((ev) => ev.getDesc() === 'Birkat Hachamah');
expect(typeof ev2).toBe('object');
expect(ev2.getDate().toString()).toBe('29 Adar II 5993');
});

test('getHolidaysForYear-throw', () => {
expect(() => {
getHolidaysForYear_(-1);
}).toThrow('Hebrew year -1 out of range 1-32658');
});
34 changes: 17 additions & 17 deletions test/getHolidaysOnDate.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {HebrewCalendar} from '../src/hebcal';
import {HDate} from '@hebcal/hdate';
import {Event} from '../src/event';
import {getHolidaysOnDate} from '../src/holidays';

jest.mock('quick-lru', () => {
return jest.fn().mockImplementation(() => {
Expand All @@ -20,7 +20,7 @@ test('getHolidaysOnDate', () => {
for (const item of expected) {
const dt = item.dt;
const desc = item.desc;
const ev = HebrewCalendar.getHolidaysOnDate(dt);
const ev = getHolidaysOnDate(dt);
if (typeof desc === 'undefined') {
expect(ev).toBe(undefined);
} else {
Expand All @@ -36,39 +36,39 @@ test('getHolidaysOnDate', () => {
test('getHolidaysOnDate-il', () => {
const dtShavuot1 = new Date(2021, 4, 17);
const dtShavuot2 = new Date(2021, 4, 18);
const events0 = HebrewCalendar.getHolidaysOnDate(dtShavuot1);
const events0 = getHolidaysOnDate(dtShavuot1);
expect(events0).toBeDefined();
expect((events0 as Event[]).length).toBe(2);

const events1il = HebrewCalendar.getHolidaysOnDate(dtShavuot1, true);
const events1il = getHolidaysOnDate(dtShavuot1, true);
expect(events1il).toBeDefined();
expect((events1il as Event[]).length).toBe(1);
expect((events1il as Event[])[0].getDesc()).toBe('Shavuot');

const events1diaspora = HebrewCalendar.getHolidaysOnDate(dtShavuot1, false);
const events1diaspora = getHolidaysOnDate(dtShavuot1, false);
expect(events1diaspora).toBeDefined();
expect((events1diaspora as Event[]).length).toBe(1);
expect((events1diaspora as Event[])[0].getDesc()).toBe('Shavuot I');

const events2d = HebrewCalendar.getHolidaysOnDate(dtShavuot2, false);
const events2d = getHolidaysOnDate(dtShavuot2, false);
expect(events2d).toBeDefined();
expect((events2d as Event[]).length).toBe(1);
expect((events2d as Event[])[0].getDesc()).toBe('Shavuot II');

const events2il = HebrewCalendar.getHolidaysOnDate(dtShavuot2, true);
const events2il = getHolidaysOnDate(dtShavuot2, true);
expect(events2il).toBeDefined();
expect((events2il as Event[]).length).toBe(0); // expected no Shavuot II in Israel
});

test('getHolidaysOnDate-cacheHit', () => {
const dt = new Date(2023, 11, 13);
const hd = new HDate(dt);
const ev1 = HebrewCalendar.getHolidaysOnDate(dt, false);
const ev2 = HebrewCalendar.getHolidaysOnDate(hd, false);
const ev3 = HebrewCalendar.getHolidaysOnDate(dt, true);
const ev4 = HebrewCalendar.getHolidaysOnDate(hd, true);
const ev5 = HebrewCalendar.getHolidaysOnDate(dt);
const ev6 = HebrewCalendar.getHolidaysOnDate(hd);
const ev1 = getHolidaysOnDate(dt, false);
const ev2 = getHolidaysOnDate(hd, false);
const ev3 = getHolidaysOnDate(dt, true);
const ev4 = getHolidaysOnDate(hd, true);
const ev5 = getHolidaysOnDate(dt);
const ev6 = getHolidaysOnDate(hd);
expect(ev1).toEqual(ev2);
expect(ev1).toEqual(ev3);
expect(ev1).toEqual(ev4);
Expand All @@ -78,16 +78,16 @@ test('getHolidaysOnDate-cacheHit', () => {

test('getHolidaysOnDate-neg-cacheHit', () => {
const hd = new HDate(3, 'Cheshvan', 5771);
const ev1 = HebrewCalendar.getHolidaysOnDate(hd, false);
const ev2 = HebrewCalendar.getHolidaysOnDate(hd, false);
const ev3 = HebrewCalendar.getHolidaysOnDate(hd.greg(), false);
const ev1 = getHolidaysOnDate(hd, false);
const ev2 = getHolidaysOnDate(hd, false);
const ev3 = getHolidaysOnDate(hd.greg(), false);
expect(ev1).toBe(undefined);
expect(ev2).toBe(undefined);
expect(ev3).toBe(undefined);
});

test('getHolidaysOnDate does not include Mevarchim Chodesh', () => {
// {date: '2011-05-28', desc: 'Shabbat Mevarchim Chodesh Sivan'}
const events = HebrewCalendar.getHolidaysOnDate(new Date(2011, 4, 28), false);
const events = getHolidaysOnDate(new Date(2011, 4, 28), false);
expect(events).toBe(undefined);
});
6 changes: 3 additions & 3 deletions test/hallel.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {HDate, months} from '@hebcal/hdate';
import {HebrewCalendar} from '../src/hebcal';
import {getHolidaysForYearArray} from '../src/holidays';
import {hallel_} from '../src/hallel';

jest.mock('quick-lru', () => {
Expand All @@ -9,7 +9,7 @@ jest.mock('quick-lru', () => {
});

test('hallel', () => {
const ev1 = HebrewCalendar.getHolidaysForYearArray(5781, false);
const ev1 = getHolidaysForYearArray(5781, false);
expect(hallel_(ev1, new HDate(14, months.NISAN, 5781))).toBe(0);
expect(hallel_(ev1, new HDate(15, months.NISAN, 5781))).toBe(2);
expect(hallel_(ev1, new HDate(16, months.NISAN, 5781))).toBe(2);
Expand All @@ -19,7 +19,7 @@ test('hallel', () => {
expect(hallel_(ev1, new HDate(29, months.KISLEV, 5781))).toBe(2);
expect(hallel_(ev1, new HDate(21, months.KISLEV, 5781))).toBe(0);

const ev2 = HebrewCalendar.getHolidaysForYearArray(5781, true);
const ev2 = getHolidaysForYearArray(5781, true);
expect(hallel_(ev2, new HDate(17, months.NISAN, 5781))).toBe(1);
expect(hallel_(ev2, new HDate(28, months.NISAN, 5781))).toBe(0);
expect(hallel_(ev2, new HDate(30, months.NISAN, 5781))).toBe(1);
Expand Down
6 changes: 0 additions & 6 deletions test/hebcal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,12 +476,6 @@ test('year0', () => {
expect(events.length).toBe(82);
});

test('getHolidaysForYear-throw', () => {
expect(() => {
HebrewCalendar.getHolidaysForYear(-1);
}).toThrow('Hebrew year -1 out of range 1-32658');
});

test('version', () => {
const version = HebrewCalendar.version();
expect(version.substring(0, version.indexOf('.'))).toBe('5');
Expand Down

0 comments on commit 40a065a

Please sign in to comment.