// Computations concerning the Hebrew Calendar
// ===========================================
// Copyright (c) 2001 Henk-Reints.nl
//
// (use monospace font and landscape to print this file - it's wide)
//
// The current definition of the Hebrew calendar is generally said to have been set down by the Sanhedrin
// president Hillel II in approximately AD 359. The original details of his calendar are, however, uncertain.
// (citation from Claus Tonderings Calendar FAQ)
// [HR: Sanhedrin is a sort of supreme court]
//
//**********************************************************************************************************************************
//** TO DO:
//**
//**	implement an algorithm that generates Hebrew Calendars based on astronomical data.
//**	i.e. a system that COULD have been used based on observations (but probably wasn't, see note below).
//**
//**	first day of each month:
//**	  find instant of new moon
//**	  REPEAT
//**	    find instant of BEGINNING of NEXT moonset, i.e. when the moon's lower edge "lies on the horizon"
//**	  UNTIL at that moment the illuminated fraction is large enough (say 1% ?)
//**		AND it is dark enough (i.e. top of sun >= 3 degrees below horizon = halfway civil twilight)
//**	  assume this is a visible crescent and the month begins
//**	  IF the month is Tishrei
//**	  THEN check Dehiyyah ADU (1 Tishrei on Su,We,Fr) and delay by one day if necs
//**
//**	intercalation: ASSUME they knew about the 365 day solar year length and ASSUME they could and did
//**	observe and register the vernal equinox, then they COULD have used that to decide on inserting a
//**	leap month or not.
//**
//**	(E = day of equinox)		leap year			normal year
//**					------------------		------------------
//**	E-14				<= 1=Nisan	<= E-4		< 1=Nisan	<= E+15
//**					   2				< 2
//**	E-14 + 1*59	= E+45		<= 3		<= E+55		< 3		<= E+74
//**					   4				< 4
//**	E-14 + 2*59	= E+104		<= 5		<= E+114	< 5		<= E+133
//**					   6				< 6
//**	E-14 + 3*59	= E+163		<= 7=Tishrei	<= E+173	< 7=Tishrei	<= E+192
//**					   8				< 8
//**	E-14 + 4*59	= E+222		<= 9		<= E+232	< 9		<= E+251
//**					   10				< 10
//**	E-14 + 5*59	= E+281		<= 11=Shvat	<= E+291	< 11		<= E+310
//**			  E+310.5	<= 12=Adar1	<= E+320.5	< 12=Adar	<= E+339.5
//**	E-14 + 6*59	= E+340		<= 13=Adar2	<= E+350	< 1=Nisan	<= E+369
//**	E+365-14 + 18	= E+369 	<= 1=Nisan	<= E+380
//**
//**	algorithm:
//**	- Find E = true (observable) equinox of year before
//**	- Find first observable new crescent L >= E+310
//**	- If L <= E+320 then Nisan = L + 2 months, else Nisan = L + 1 month.
//**
//**	Note:
//**	I'm quite sure that this way of intercalation is NOT historically correct, but it provides a reasonable guess.
//**	For historical survey, say on the month Nisan (Crucifiction), one should also check Adar2 (in case MY leap month
//**	is wrong and it actually was Nisan, as well as Iyyar (in case I missed a leap month that was actually there)
//**	The insertion of intercalary months was not based on astronomical observation of the equinox but a month was
//**	added "if the crops did not grow" (or other criteria like that can be found on the WWW).
//** END OF TO DO
//**********************************************************************************************************************************
//
// On the Hebrew calendar, Nisan is month number 1, but the years are counted in Tishrei = 7,
// which merely complicates the mathematics of the calendar, so in THIS library I use the following
// month numbers (to be considered just a month ID or synonym instead of a ranking sequence number):
// Tishrei = 1, (...) Adar1 = 6, Adar2 = 7, Nisan = 8, (...) Elul = 13.
// Nisan is ALWAYS month 8 in this library, whether the year is leap or not.
// For Adar the following applies:
// 	leap years:	length[6] = 30	name[6] = "adar1"	// this is the leap month
//			length[7] = 29	name[7] = "adar2"	// this is the "regular" adar
// 	non-leap years:	length[6] = 29	name[6] = "adar"	// in non leap years shift adar one place forward
//			length[7] =  0	name[7] = ""		// for proper conversion to official hebrew month number
//
// I use a "HebrewDay" wich is something like the JulianDay. HebrewDay is the number of days
// since (i.e. after) the Shabbat just BEFORE 1 Tishrei 1, which itself is HebrewDay 2 (a Monday).
// (The first day of genesis is presumed to be the Sunday before 1 Tishrei 1.)
//
// The 4 Dehiyyot (postponement rules):
//
// ADU			If the Molad of Tishrei occurs on a Sunday, Wednesday or Friday
//			then Rosh Hashannah is postponed to the next day.
//			The name ADU is an acronym formed from the Hebrew letters
//			alef (=1 for Sunday) daled (=4 for Wednedsday) vov (=6 for Friday).
//			It prevents Yom Kippur (10 Tishrei) from occurring on either side of Shabbat,
//			as would happen if Rosh Hashannah where on Wednesday or Friday.
//			It also prevents Hoshannah Rabbah (21 Tishrei) from coming on a Shabbat,
//			as would happen if Rosh Hashannah were allowed to begin on Sunday.
//
// Molad Zakein		The name for this rule is often translated as the "old moon" or "obsolete moon" rule.
//			If the Molad of Tishrei occurs at 18 hours (ie, noon) or later of a permissible day
//			then the first day of Rosh Hashannah is postponed to the next allowable day. 
//			Some noteworthy scholars have suggested that this rule will garantee the visibility
//			of the new moon on the first day of Rosh Hashannah. 
//			However, simple calendar arithmetic very strongly suggests that the molad zakein rule
//			is no more than an arithmetical device which ensures that the calculated time of any
//			molad does not exceed the first day of any Hebrew month.
//		Remark by Henk Reints:
//			This rule implicitly keeps track of the very small shifting of the 19 year cycle,
//			which shifts 8 days in 25 centuries on the Gregorian Calendar. It simply adjusts
//			the year length whenever necessary.
//			Visibility of the new lunar crescent cannot ever be guaranteed. it is only visible
//			just after sunset and for a very young crescent the observer must be on the right
//			place on earth under ideal atmospheric circumstances. The known and certified world
//			record as far as I can find on the web is ca. 15.4 hours of moon age and usually the
//			moon is over 24 hours old before it is visible at all. This uncertainty is exactly the
//			reason why modern astronomers define new moon as the moment of conjuction with the sun,
//			because that IS predictable quite accurately and it is independent of its observation.
//
// GaTaRad		If the Molad of Tishrei for a common year is on Tuesday, 9 hours, 204 parts or later,
//			then Rosh Hashannah is postponed to Thursday. Gatarad eliminates all 356 day Hebrew years.
//			It is not found in the Talmud.
//
// BeTU'TeKaPoT		If the Molad of Tishrei following a leap year is on Monday, 15 hours, 589 parts or later,
//			then Rosh Hashannah is postponed to Tuesday. This rule eliminates all 382 day Hebrew years.
//			It is not found in the Talmud.
//
//	HR: Usually the Dehiyyot are given in the order above, but I have implemented them as follows:
//
//		first: if either one of Molad Zakein, BeTU'TeKaPoT, or GaTaRad applies then add 1 day
//		second: if ADU applies then add a(nother) day
//
//	BeTU'TeKaPoT and GaTaRad cannot be effective both (because they test for different days) and Molad Zakein
//	implicitly takes care of both. Since all Dehiyyot refer to the Molad and not the already delayed Rosh HasHanna
//	they cannot all be effective at the same time (to my opinion) so I test for either one of them and then add a
//	day if necs. Only ADU can be simultaneously effective, since it has nothing to do with the moon. I have checked
//	my implementation against different Hebrew Calendars already available on the web and I could not yet find any
//	difference.
//
// Many sources state that "complex mathematical rules" are involved to compute the Hebrew calendar and that one should not
// attempt to calculate it himself, but I found it VERY EASY to implement. The rules are SIMPLE, not complex.
//
// Reference used to build this library: Hebrew Calendar Science and Myths, http://www.geocities.com/Athens/1584/
// --------------------------------------------------------------------------------------------------------------------------------
function toRealHebrewMonthNo (monthNo, leap)	// convert month no. as used HERE (Nisan = 8) to real Hebrew number (Nisan = 1)
{
	return (monthNo + 5) % 13 + 1
}
// --------------------------------------------------------------------------------------------------------------------------------
function fromRealHebrewMonthNo (monthNo, leap)	// convert real Hebrew month no. (Nisan = 1) to value for use HERE (Nisan = 8)
{
	return (monthNo + 6) % 13 + 1
}
// --------------------------------------------------------------------------------------------------------------------------------
function HebrewMonthNames (leap)	// get array with month names;
{					// each element is itself an array with different spellings for the same month;
	// element 0 is preferred spelling, so use HebrewMonthNames(leap)[monthNumber][0] as the month name.
	// function HebrewMonthNumber uses the other spellings for flexible interpretation of month names whilst
	// converting them to numbers. I have entered all names I found on Internet, and what I found to be the most
	// abundant is entered here as preferred name. Add your own alternative spellings if needed,
	// but ALL MONTH NAMES MUST BE DEFINED IN LOWERCASE ONLY (doesn't that look contradictory?)
	// function HebrewMonthNumbers relies thereon!
	// for Adar short names "a1" and "a2" are included, just for my private convenience - I lk 2 tp s ltl s psbl

	return	[[""]				// skip element 0 for same indexing as result of function HebrewCalendar
		,["tishrei","tisri","tishri","tishre","etanim","ethanim"]
		,["cheshvan","heshvan","chesvan","hesvan","marchesvan","marhesvan","bul","heshwan","marheshwan"]
		,["kislev","kislew","chislev"]
		,["tevet","tebet","tebeth"]
		,["shvat","shevat","shebat","sebat","sjebat","shebhat"]
		,leap ? ["adar1","adar 1","adar i" ,"a1"]                                 : ["adar"]
		,leap ? ["adar2","adar 2","adar ii","a2","veadar","adar sjeni","we-adar"] : [""]
		,["nisan","nissan","abib"]
		,["iyyar","iyar","ijar","ziv","ziw"]
		,["sivan","siwan"]
		,["tamuz","tammuz"]
		,["av","ab","abh"]
		,["elul"]
		]
}
// --------------------------------------------------------------------------------------------------------------------------------
function HebrewMonthNumber (monthName, leap)	// find month number for name by unique match of first few characters
{						// monthName can be a unique abbreviation of a valid month name
	// if function HebrewMonthNames defines the same name more than once then -2 is returned (coding error in THIS file),
	// if monthName not found then -1 is returned, if ambiguous then 0, else month number is returned.
	// examples:	"Ti" or "Tis"	returns  1 (Tishrei)
	//		"Tissue"	returns -1 (not found)
	//		"T"		returns  0 (ambiguous: Tishrei, Tevet, Tamuz ?)
	//		"N"		returns  8 (Nisan)

	var mn = HebrewMonthNames (leap)
	var x  = monthName.toLowerCase()
	var m  = 0	// count exact matches
	var n  = 0	// count abbreviated matches
	var k
	for (var i = 1; i < mn.length; i++)					// check them all
	{	for (var j = 0; j < mn[i].length; j++)
		{	if	(mn[i][j] == x)			{k = i; m++}	// exact match
			else if	(mn[i][j].indexOf(x) == 0)	{k = i; n++}	// abbreviated match
		}
	}
	if (m > 1) return -2			// HebrewMonthNames has defined same name twice: CODING ERROR!
	if (m < 1) m = n			// only if no exact match then use abbreviation count
	return m < 1 ? -1 : m > 1 ? 0 : k	// return proper result
}
// --------------------------------------------------------------------------------------------------------------------------------
function HebrewCalendar (HebrewYear)	// returns array with HebrewDay of Rosh HaShana (1 Tishrei) and month lengths
{
	var result = [Rosh_HaShana(HebrewYear),30,29,30,29,30,29,0,30,29,30,29,30,29]
	var n = Rosh_HaShana(HebrewYear+1) - result[0]	// actual length of year
	if (n > 355)					// leap?
	{	result[6]++				// Adar1 has 30 days
		result[7] = 29				// Adar2 has 29
		m = 384					// regular (kesidrah) leap year length
	} else	m = 354					// regular (kesidrah) non-leap year length
	if (n < m) result[3]--				// deficient year (haser)
	if (n > m) result[2]++				// complete year (shalem)
	return result
}
// --------------------------------------------------------------------------------------------------------------------------------
function isHebrewLeap (HebrewYear)
{
	var GUCHADZaT = "1001001010010010010"			// mark which years are leap in 19 year cycle
	return GUCHADZaT.charAt ((HebrewYear%19+19)%19) * 1	// get corresponding value
}
// --------------------------------------------------------------------------------------------------------------------------------
function Rosh_HaShana (HebrewYear)	// computes day of Rosh HaShana (first day of new year = 1 Tishrei) of a given HebrewYear
{					// returns HebrewDay number (1 Tishrei 1 = HD 2)
	var MoladPeriod	= (29 * 24 + 12) * 1080 + 793				// average synodic month (29d,12h,44m,3.333s)
	var BaHaRaD	= ( 2 * 24 +  5) * 1080 + 204				// Molad shel Tohu. (Molad of 1 Tishrei 1)
	var ADU		= "0100101"						// mark forbidden days for Rosh HaShana
	var dayparts	= 24 * 1080						// parts per day, 1 hour = 1080 parts (halakhim)
	var months	= Math.floor ( (235 * HebrewYear - 234) / 19)		// no. of months since BaHaRaD
	var Molad	= BaHaRaD + months * MoladPeriod			// absolute time of Molad (in parts)
	var day		= Math.floor (Molad / dayparts)				// days since 1 Tishrei 1 of this Molad
	var parts	= Molad % dayparts					// parts within day
	if ((                parts >= 18 * 1080      )					// Dehiyyah Molad Zakein
	||  (day % 7 == 3 && parts >=  9 * 1080 + 204)					// Dehiyyah GaTaRad
	||  (day % 7 == 2 && parts >= 15 * 1080 + 589 && isHebrewLeap(HebrewYear-1) )	// Dehiyyah BeTU'TeKaPoT
	   )				day++
	if (ADU.charAt (day % 7) * 1)	day++					// Dehiyyah ADU
	return day								// return HebrewDay
}
// --------------------------------------------------------------------------------------------------------------------------------
function HebrewDayFromDate (HebrewYear, month, day)	// convert year,month,day to HebrewDay
{
	var c = HebrewCalendar (HebrewYear)		// get this year's calendar
	var d = c[0]					// Rosh HaShana of the year as a HebrewDay
	for (var i = 1; i < month; i++) {d += c[i] } 	// add elapsed month lenghts
	return d + day - 1				// add the day, but Rosh HaShana already is 1 so subtract 1
}
// --------------------------------------------------------------------------------------------------------------------------------
function HebrewDateFromDay (HebrewDay)		// converts HebrewDay to Hebrew date (i.e. year, month, day)
{								// must find Rosh HaShana of corresponding year, then it' easy...
	var MoladPeriod	= (29 * 24 + 12) * 1080 + 793			// average synodic month (29d,12h,44m,3.333s)
	var BaHaRaD	= ( 2 * 24 +  5) * 1080 + 204			// Molad shel Tohu. (Molad of 1 Tishrei 1)
	var months	= (HebrewDay * 24* 1080 - BaHaRaD) /MoladPeriod	// no. of months
	var year	= Math.round ( (months * 19 + 234) /235)	// approximate Hebrew year (best guess at this moment)
	if (Rosh_HaShana (year) > HebrewDay) year--			// could be 1 to much
	var c = HebrewCalendar (year)					// get the calendar with month lengths
	var d = HebrewDay + 1 - c[0]					// get day within year (c[0] = Rosh HaShana)
	var m = 1							// init month to Tishrei
	while (d > c[m] ) {d -= c[m++] }				// subtract month length and increment month while necs
	return [year, m, d]
}
// --------------------------------------------------------------------------------------------------------------------------------
function JulianDayFromHebrewDay (HebrewDay, hours, parts)	// convert Hebrew day+hours+parts to Julian Day
{
	var result = 347995 + HebrewDay				// + JDoffset from BaHaRaD-2d
	result += arguments.length < 2 ? 1 : 0.15208		// if not whole days then time offset for 18:00 Jerusalem Time
	if (arguments.length > 1) result += hours /  24		//						\\ (15:39 UTC)
	if (arguments.length > 2) result += parts / (24 * 1080)
	return result
}
// --------------------------------------------------------------------------------------------------------------------------------
function HebrewDayFromJulianDay (JD)	// convert JulianDay to HebrewDay and return Array [day, parts within day]
{					// (ignore the hour unit, it only complicates things...)
	var hd = JD - 347995.15208					// subtract offset
	return [Math.floor (hd), Math.round ( (hd % 1) * 24 * 1080) ]	// this is it... (hd < 2 should be marked invalid?)
}
// --------------------------------------------------------------------------------------------------------------------------------
// Because the Hebrew calendar does not have the same "speed" as the Gregorian
// (an average Hebrew year is a bit longer tha an average Gregorian year),
// the next 2 functions to convert Hebrew and Gregorian years in both directions
// do not simply add or subtract 3760, but the computation is done via the Julian
// Day and Hebrew Day, which makes the conversion universal and "timeless":
// --------------------------------------------------------------------------------------------------------------------------------
function HebrewYearFromGregorian (GregorianYear)	// HebrewYear that contains Gregorian January 1
{	var y = GregorianYear-1
	return HebrewDateFromDay (1373430 + y*365 + Math.floor(y/4) + Math.floor(y/400) - Math.floor(y/100) )[0]
}
// --------------------------------------------------------------------------------------------------------------------------------
function GregorianYearFromHebrew (HebrewYear)		// GregorianYear that contains 1 Nisan
{
	var j = JulianDayFromHebrewDay (HebrewDayFromDate (HebrewYear, 8, 1) ) - 1721426
	var n, L=0, y=1, a=[[146097,400],[36524,100],[1461,4],[365,1]]
	for (var i = 0; i < a.length; i++)
	{	if (i%2==0 && (j+1)%a[i][0]==0) L=1
		n = Math.floor(j/a[i][0])
		j -= n*a[i][0]
		y += n*a[i][1]
	}
	return y-L
}
// --------------------------------------------------------------------------------------------------------------------------------
// [end of file]
