hebcal-fixed
Version:
An easy to use, richly-featured, perpetual Jewish Calendar API
604 lines (545 loc) • 16 kB
JavaScript
/*
Hebcal - A Jewish Calendar Generator
Copyright (C) 1994-2004 Danny Sadinoff
Portions Copyright (c) 2002 Michael J. Radwin. All Rights Reserved.
https://github.com/hebcal/hebcal-js
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 3 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/>.
Danny Sadinoff can be reached at danny@sadinoff.com
Michael Radwin has made significant contributions as a result of
maintaining hebcal.com.
The JavaScript code was completely rewritten in 2014 by Eyal Schachter.
*/
var c = require('./common'),
HDate = require('./hdate'),
gematriya = require('gematriya');
var __cache = {};
// for byte optimizations
var dayOnOrBefore = c.dayOnOrBefore,
months = c.months,
days = c.days,
TISHREI = months.TISHREI,
KISLEV = months.KISLEV,
NISAN = months.NISAN,
SAT = days.SAT,
getDay = 'getDay',
abs = 'abs',
Shabbat = 'Shabbat',
Shabbos = 'Shabbos';
function Chanukah(day) {
return ['Chanukah: Candle ' + day, 0, 'חנוכה: נר ' + gematriya(day)];
}
function CHM(desc) {
return [desc[0] + ' (CH"M)', desc[1] ? desc[1] + ' (CH"M)' : desc[1], desc[2] ? desc[2] + ' )חה"ם(' : desc[2]];
}
function Sukkot(day) {
return ['Sukkot: ' + day, 'Succos: ' + day, 'סוכות יום ' + gematriya(day)];
}
function Pesach(day) {
return ['Pesach: ' + day, 0, 'פסח יום ' + gematriya(day)];
}
var USER_EVENT = 1,
LIGHT_CANDLES = 2,
YOM_TOV_ENDS = 4,
CHUL_ONLY = 8, // chutz l'aretz (Diaspora)
IL_ONLY = 16, // b'aretz (Israel)
LIGHT_CANDLES_TZEIS = 32;
exports.masks = {
USER_EVENT : USER_EVENT,
LIGHT_CANDLES : LIGHT_CANDLES,
YOM_TOV_ENDS : YOM_TOV_ENDS,
CHUL_ONLY : CHUL_ONLY,
IL_ONLY : IL_ONLY,
LIGHT_CANDLES_TZEIS: LIGHT_CANDLES_TZEIS
};
function Event(date, desc, mask) {
var me = this;
me.date = new HDate(date);
me.desc = typeof desc != 'object' ? [desc] : desc;
me.USER_EVENT = !!( mask & USER_EVENT );
me.LIGHT_CANDLES = !!( mask & LIGHT_CANDLES );
me.YOM_TOV_ENDS = !!( mask & YOM_TOV_ENDS );
me.CHUL_ONLY = !!( mask & CHUL_ONLY );
me.IL_ONLY = !!( mask & IL_ONLY );
me.LIGHT_CANDLES_TZEIS = !!( mask & LIGHT_CANDLES_TZEIS );
}
Event.prototype.is = function(date, il) {
date = new HDate(date), myDate = this.date;
if (arguments.length < 2) {
//il = Event.isIL;
il = date.il;
}
if (date.getDate() != myDate.getDate() || date.getMonth() != myDate.getMonth()) {
return false;
}
if (date.getFullYear() != myDate.getFullYear()) {
return false;
}
if (il && this.CHUL_ONLY || !il && this.IL_ONLY) {
return false;
}
return true;
};
Event.prototype.masks = function() {
var me = this;
return (me.USER_EVENT && USER_EVENT) |
(me.LIGHT_CANDLES && LIGHT_CANDLES) |
(me.YOM_TOV_ENDS && YOM_TOV_ENDS) |
(me.CHUL_ONLY && CHUL_ONLY) |
(me.IL_ONLY && IL_ONLY) |
(me.LIGHT_CANDLES_TZEIS && LIGHT_CANDLES_TZEIS);
};
Event.prototype.getDesc = function(o) {
return c.LANG(this.desc, o);
};
Event.prototype.candleLighting = function() {
var date = this.date;
if (this.LIGHT_CANDLES) {
return new Date(date.sunset() - (Event.candleLighting * 60 * 1000));
} else if (this.LIGHT_CANDLES_TZEIS) {
return date.getZemanim().tzeit;
}
return null;
};
Event.prototype.havdalah = function() {
if (this.YOM_TOV_ENDS) {
return new Date(this.date.sunset().getTime() + (Event.havdalah * 60 * 1000));
}
return null;
};
Event.prototype.routine = (function(){
function routine(){
return !!~routine.names.indexOf(this.getDesc('s'));
}
routine.names = [Shabbat, 'Erev ' + Shabbat];
return routine;
})();
Event.isIL = false;
Event.candleLighting = 18;
Event.havdalah = 42;
exports.Event = Event;
exports.year = function(year) {
if (__cache[year]) {
return __cache[year];
}
var RH = new HDate(1, TISHREI, year),
pesach = new HDate(15, NISAN, year),
tmpDate;
var h = {};
function add(ev) {
if (Array.isArray(ev)) {
ev.forEach(function(e){
add(e);
});
} else {
if (h[ev.date]) {
h[ev.date].push(ev);
} else {
h[ev.date] = [ev];
}
}
}
Object.defineProperty(h, 'add', {value: add});
add([ // standard holidays that don't shift based on year
new Event(
RH,
['Rosh Hashana 1', 0, 'ראש השנה א\''],
LIGHT_CANDLES_TZEIS
), new Event(
new HDate(2, TISHREI, year),
['Rosh Hashana 2', 0, 'ראש השנה ב\''],
YOM_TOV_ENDS
), new Event(
new HDate(3 + (RH[getDay]() == days.THU), TISHREI, year), // push off to SUN if RH is THU
['Tzom Gedaliah', 0, 'צום גדליה'],
0
), new Event(
new HDate(9, TISHREI, year),
['Erev Yom Kippur', 0, 'ערב יום כיפור'],
LIGHT_CANDLES
), new Event( // first SAT after RH
new HDate(dayOnOrBefore(SAT, 7 + RH[abs]())),
[Shabbat + ' Shuva', Shabbos + ' Shuvah', 'שבת שובה'],
0
), new Event(
new HDate(10, TISHREI, year),
['Yom Kippur', 0, 'יום כיפור'],
YOM_TOV_ENDS
), new Event(
new HDate(14, TISHREI, year),
['Erev Sukkot', 'Erev Succos', 'ערב סוכות'],
LIGHT_CANDLES
), new Event(
new HDate(15, TISHREI, year),
Sukkot(1),
LIGHT_CANDLES_TZEIS | CHUL_ONLY
), new Event(
new HDate(15, TISHREI, year),
Sukkot(1),
YOM_TOV_ENDS | IL_ONLY
), new Event(
new HDate(16, TISHREI, year),
Sukkot(2),
YOM_TOV_ENDS | CHUL_ONLY
), new Event(
new HDate(16, TISHREI, year),
CHM(Sukkot(2)),
IL_ONLY
), new Event(
new HDate(17, TISHREI, year),
CHM(Sukkot(3)),
0
), new Event(
new HDate(18, TISHREI, year),
CHM(Sukkot(4)),
0
), new Event(
new HDate(19, TISHREI, year),
CHM(Sukkot(5)),
0
), new Event(
new HDate(20, TISHREI, year),
CHM(Sukkot(6)),
0
), new Event(
new HDate(21, TISHREI, year),
['Sukkot: 7 (Hoshana Raba)', 'Succos: 7 (Hoshana Raba)', 'סוכות יום ז\' )הושנע רבה('],
LIGHT_CANDLES
), new Event(
new HDate(22, TISHREI, year),
['Shmini Atzeret', 'Shmini Atzeres', 'שמיני עצרת'],
LIGHT_CANDLES_TZEIS | CHUL_ONLY
), new Event(
new HDate(22, TISHREI, year),
['Shmini Atzeret / Simchat Torah', 'Shmini Atzeres / Simchas Torah', 'שמיני עצרת / שמחת תורה'],
YOM_TOV_ENDS | IL_ONLY
), new Event(
new HDate(23, TISHREI, year),
['Simchat Torah', 'Simchas Torah', 'שמחת תורה'],
YOM_TOV_ENDS | CHUL_ONLY
), new Event(
new HDate(24, KISLEV, year),
['Erev Chanukah', 0, 'ערב חנוכה'],
0
), new Event(
new HDate(25, KISLEV, year),
Chanukah(1),
0
), new Event(
new HDate(26, KISLEV, year),
Chanukah(2),
0
), new Event(
new HDate(27, KISLEV, year),
Chanukah(3),
0
), new Event(
new HDate(28, KISLEV, year),
Chanukah(4),
0
), new Event(
new HDate(29, KISLEV, year),
Chanukah(5),
0
), new Event(
new HDate(30, KISLEV, year), // yes, i know these are wrong
Chanukah(6),
0
), new Event(
new HDate(31, KISLEV, year), // HDate() corrects the month automatically
Chanukah(7),
0
), new Event(
new HDate(32, KISLEV, year),
Chanukah(8),
0
), new Event(
new HDate(15, months.SHVAT, year),
["Tu B'Shvat", 0, 'ט"ו בשבט'],
0
), new Event(
new HDate(dayOnOrBefore(SAT, pesach[abs]() - 43)),
[Shabbat + ' Shekalim', Shabbos + ' Shekalim', 'שבת שקלים'],
0
), new Event(
new HDate(dayOnOrBefore(SAT, pesach[abs]() - 30)),
[Shabbat + ' Zachor', Shabbos + ' Zachor', 'שבת זכור'],
0
), new Event(
new HDate(pesach[abs]() - (pesach[getDay]() == days.TUE ? 33 : 31)),
["Ta'anit Esther", "Ta'anis Esther", 'תענית אסתר'],
0
), new Event(
new HDate(13, months.ADAR_II, year),
['Erev Purim', 0, 'ערב פורים'],
0
), new Event(
new HDate(14, months.ADAR_II, year),
['Purim', 0, 'פורים'],
0
), new Event(
new HDate(15, months.ADAR_II, year),
['Shushan Purim', 0, 'שושן פורים'],
0
), new Event(
new HDate(dayOnOrBefore(SAT, pesach[abs]() - 14) - 7),
[Shabbat + ' Parah', Shabbos + ' Parah', 'שבת פרה'],
0
), new Event(
new HDate(dayOnOrBefore(SAT, pesach[abs]() - 14)),
[Shabbat + ' Hachodesh', Shabbos + ' Hachodesh', 'שבת החודש'],
0
), new Event(
new HDate(dayOnOrBefore(SAT, pesach[abs]() - 1)),
[Shabbat + ' HaGadol', Shabbos + ' HaGadol', 'שבת הגדול'],
0
), new Event(
// if the fast falls on Shabbat, move to Thursday
pesach.prev()[getDay]() == SAT ? pesach.onOrBefore(days.THU) : new HDate(14, NISAN, year),
["Ta'anit Bechorot", "Ta'anis Bechoros", 'תענית בכורות'],
0
), new Event(
new HDate(14, NISAN, year),
['Erev Pesach', 0, 'ערב פסח'],
LIGHT_CANDLES
), new Event(
new HDate(15, NISAN, year),
Pesach(1),
LIGHT_CANDLES_TZEIS | CHUL_ONLY
), new Event(
new HDate(15, NISAN, year),
Pesach(1),
YOM_TOV_ENDS | IL_ONLY
), new Event(
new HDate(16, NISAN, year),
Pesach(2),
YOM_TOV_ENDS | CHUL_ONLY
), new Event(
new HDate(16, NISAN, year),
CHM(Pesach(2)),
IL_ONLY
), new Event(
new HDate(16, NISAN, year),
['Start counting Omer', 0, 'התחלת ספירת העומר'],
0
), new Event(
new HDate(17, NISAN, year),
CHM(Pesach(3)),
0
), new Event(
new HDate(18, NISAN, year),
CHM(Pesach(4)),
0
), new Event(
new HDate(19, NISAN, year),
CHM(Pesach(5)),
0
), new Event(
new HDate(20, NISAN, year),
CHM(Pesach(6)),
LIGHT_CANDLES
), new Event(
new HDate(21, NISAN, year),
Pesach(7),
LIGHT_CANDLES_TZEIS | CHUL_ONLY
), new Event(
new HDate(21, NISAN, year),
Pesach(7),
YOM_TOV_ENDS | IL_ONLY
), new Event(
new HDate(22, NISAN, year),
Pesach(8),
YOM_TOV_ENDS | CHUL_ONLY
), new Event(
new HDate(14, months.IYYAR, year),
['Pesach Sheni', 0, 'פסח שני'],
0
), new Event(
new HDate(18, months.IYYAR, year),
["Lag B'Omer", 0, 'ל"ג בעומר'],
0
), new Event(
new HDate(5, months.SIVAN, year),
['Erev Shavuot', 'Erev Shavuos', 'ערב שבועות'],
LIGHT_CANDLES
), new Event(
new HDate(6, months.SIVAN, year),
['Shavuot 1', 'Shavuos 1', 'שבועות א\''],
LIGHT_CANDLES_TZEIS | CHUL_ONLY
), new Event(
new HDate(6, months.SIVAN, year),
['Shavuot', 'Shavuos', 'שבועות'],
YOM_TOV_ENDS | IL_ONLY
), new Event(
new HDate(7, months.SIVAN, year),
['Shavuot 2', 'Shavuos 2', 'שבועות ב\''],
YOM_TOV_ENDS | CHUL_ONLY
), new Event(
new HDate(dayOnOrBefore(SAT, new HDate(1, TISHREI, year + 1)[abs]() - 4)),
['Leil Selichot', 'Leil Selichos', 'ליל סליחות'],
0
), new Event(
new HDate(29, months.ELUL, year),
['Erev Rosh Hashana', 0, 'ערב ראש השנה'],
LIGHT_CANDLES
)
]);
tmpDate = new HDate(10, months.TEVET, year);
if (tmpDate[getDay]() == SAT) {
tmpDate = tmpDate.next();
}
add(new Event(
tmpDate,
["Asara B'Tevet", 0, 'עשרה בטבת'],
0
));
if (c.LEAP(year)) {
add(new Event(
new HDate(14, months.ADAR_I, year),
['Purim Katan', 0, 'פורים קטן'],
0
));
add(new Event(
new HDate(15, months.ADAR_I, year),
['Shushan Purim Katan', 0, 'שושן פורים קטן'],
0
));
}
if (year >= 5711) { // Yom HaShoah first observed in 1951
tmpDate = new HDate(27, NISAN, year);
/* When the actual date of Yom Hashoah falls on a Friday, the
* state of Israel observes Yom Hashoah on the preceding
* Thursday. When it falls on a Sunday, Yom Hashoah is observed
* on the following Monday.
* http://www.ushmm.org/remembrance/dor/calendar/
*/
if (tmpDate[getDay]() == days.FRI) {
tmpDate = tmpDate.prev();
} else if (tmpDate[getDay]() == days.SUN) {
tmpDate = tmpDate.next();
}
add(new Event(
tmpDate,
['Yom HaShoah', 0, 'יום השואה'],
0
));
}
add(atzmaut(year));
if (year >= 5727) { // Yom Yerushalayim only celebrated after 1967
add(new Event(
new HDate(29, months.IYYAR, year),
['Yom Yerushalayim', 0, 'יום ירושלים'],
0
));
}
tmpDate = new HDate(17, months.TAMUZ, year);
if (tmpDate[getDay]() == SAT) {
tmpDate = tmpDate.next();
}
add(new Event(
tmpDate,
["Shiva-Asar B'Tamuz", 0, "צום יז' בתמוז"],
0
));
tmpDate = new HDate(9, months.AV, year);
if (tmpDate[getDay]() == SAT) {
tmpDate = tmpDate.next();
}
add(new Event(
new HDate(dayOnOrBefore(SAT, tmpDate[abs]())),
[Shabbat + ' Chazon', Shabbos + ' Chazon', 'שבת חזון'],
0
));
add(new Event(
tmpDate.prev(),
["Erev Tish'a B'Av", 0, 'ערב תשעה באב'],
0
));
add(new Event(
tmpDate,
["Tish'a B'Av", 0, 'תשעה באב'],
0
));
add(new Event(
new HDate(dayOnOrBefore(SAT, tmpDate[abs]() + 7)),
[Shabbat + ' Nachamu', Shabbos + ' Nachamu', 'שבת נחמו'],
0
));
for (var day = 6; day < c.daysInYear(year); day += 7) {
add(new Event(
new HDate(dayOnOrBefore(SAT, new HDate(1, TISHREI, year)[abs]() + day)),
[Shabbat, Shabbos, 'שבת'],
YOM_TOV_ENDS
));
add(new Event(
new HDate(dayOnOrBefore(days.FRI, new HDate(1, TISHREI, year)[abs]() + day)),
['Erev ' + Shabbat, 'Erev ' + Shabbos, 'ערב שבת'],
LIGHT_CANDLES
));
}
for (var month = 1; month <= c.MONTH_CNT(year); month++) {
if ((month == NISAN ? c.daysInMonth(c.MONTH_CNT(year - 1), year - 1) :
c.daysInMonth(month - 1, year)) == 30) {
add(new Event(
new HDate(1, month, year),
['Rosh Chodesh 2', 0, "ראש חודש ב'"],
0
));
add(new Event(
new HDate(30, month - 1, year),
['Rosh Chodesh 1', 0, "ראש חודש א'"],
0
));
} else if (month !== TISHREI) {
add(new Event(
new HDate(1, month, year),
['Rosh Chodesh', 0, 'ראש חודש'],
0
));
}
if (month == months.ELUL) {
continue;
}
add(new Event(
new HDate(29, month, year).onOrBefore(SAT),
[Shabbat + ' Mevarchim', Shabbos + ' Mevorchim', 'שבת מברכים'],
0
));
}
return __cache[year] = h;
};
function atzmaut(year) {
if (year >= 5708) { // Yom HaAtzma'ut only celebrated after 1948
var tmpDate = new HDate(1, months.IYYAR, year), pesach = new HDate(15, NISAN, year);
if (pesach[getDay]() == days.SUN) {
tmpDate.setDate(2);
} else if (pesach[getDay]() == SAT) {
tmpDate.setDate(3);
} else if (year < 5764) {
tmpDate.setDate(4);
} else if (pesach[getDay]() == days.TUE) {
tmpDate.setDate(5);
} else {
tmpDate.setDate(4);
}
return [new Event(
tmpDate,
['Yom HaZikaron', 0, 'יום הזיכרון'],
0
), new Event(
tmpDate.next(),
["Yom HaAtzma'ut", 0, 'יום העצמאות'],
0
)];
}
return [];
}
exports.atzmaut = atzmaut;