From 40a065ab0ed725fb3ab7d160c3cd7fe621ba3bdc Mon Sep 17 00:00:00 2001 From: "Michael J. Radwin" Date: Sun, 3 Nov 2024 12:20:41 -0800 Subject: [PATCH] Export getHolidaysOnDate as a function outside of HebrewCalendar wrapper class #475 --- src/hebcal.ts | 55 ++++++--------------------------- src/holidays.ts | 55 +++++++++++++++++++++++++++++++++ src/index.ts | 2 +- test/getHolidaysForYear.spec.js | 26 ++++++++++------ test/getHolidaysOnDate.spec.ts | 34 ++++++++++---------- test/hallel.spec.ts | 6 ++-- test/hebcal.spec.ts | 6 ---- 7 files changed, 103 insertions(+), 81 deletions(-) diff --git a/src/hebcal.ts b/src/hebcal.ts index acadd903..3feaef0b 100644 --- a/src/hebcal.ts +++ b/src/hebcal.ts @@ -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'; @@ -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, @@ -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); } /** @@ -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); } /** @@ -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); } @@ -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; } diff --git a/src/holidays.ts b/src/holidays.ts index 08441744..7c815870 100644 --- a/src/holidays.ts +++ b/src/holidays.ts @@ -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; +} diff --git a/src/index.ts b/src/index.ts index f65cd160..5c6bf6ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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'; diff --git a/test/getHolidaysForYear.spec.js b/test/getHolidaysForYear.spec.js index 2d7a3f0c..a2273f02 100644 --- a/test/getHolidaysForYear.spec.js +++ b/test/getHolidaysForYear.spec.js @@ -1,4 +1,7 @@ -import {HebrewCalendar} from '../src/hebcal'; +import { + getHolidaysForYear_, + getHolidaysForYearArray, +} from '../src/holidays'; import {isoDateString} from '@hebcal/hdate'; jest.mock('quick-lru', () => { @@ -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'}, @@ -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'}, @@ -214,7 +217,7 @@ 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'}); @@ -222,7 +225,7 @@ test('getHolidaysForYear-ce', () => { }); 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'}); @@ -230,7 +233,7 @@ test('getHolidaysForYear-bce', () => { }); 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'}, @@ -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); @@ -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'); +}); diff --git a/test/getHolidaysOnDate.spec.ts b/test/getHolidaysOnDate.spec.ts index d2c8e247..06de0cdd 100644 --- a/test/getHolidaysOnDate.spec.ts +++ b/test/getHolidaysOnDate.spec.ts @@ -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(() => { @@ -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 { @@ -36,26 +36,26 @@ 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 }); @@ -63,12 +63,12 @@ test('getHolidaysOnDate-il', () => { 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); @@ -78,9 +78,9 @@ 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); @@ -88,6 +88,6 @@ test('getHolidaysOnDate-neg-cacheHit', () => { 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); }); diff --git a/test/hallel.spec.ts b/test/hallel.spec.ts index f87efed1..8ac260bb 100644 --- a/test/hallel.spec.ts +++ b/test/hallel.spec.ts @@ -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', () => { @@ -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); @@ -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); diff --git a/test/hebcal.spec.ts b/test/hebcal.spec.ts index 02001fa3..4ffd2da1 100644 --- a/test/hebcal.spec.ts +++ b/test/hebcal.spec.ts @@ -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');