Module:Next Occurrence of Hebrew Date
Usage
{{#invoke:Next Occurrence of Hebrew Date|next_occurrence_of_hebrew_date_from_date | greg_year | greg_month | greg_day | heb_month | heb_day}}
Where:
greg_year
is the Gregorian year, like 2014greg_month
is the Gregorian month number, like 12 for Decembergreg_day
is the Gregorian day of monthheb_month
can either be the Hebrew month, like Adar, or it's number, like 12 for Adarheb_day
is the Hebrew day of month
So for example, if you wanted to compute when the day of Rosh Hashanah falls out on in 2015:
{{#invoke:Next Occurrence of Hebrew Date|next_occurrence_of_hebrew_date_from_date | 2015 | 1 | 1 | 7 | 1}}
which returns September 14, 2015
There is also a convenience function, next_occurrence_of_hebrew_date, which performs the same calculation, with a start time of today's date. This is useful for determining the next occurrence of a Jewish holiday or Yahrtzeit.
{{#invoke:Next Occurrence of Hebrew Date|next_occurrence_of_hebrew_date_from_date |heb_month| heb_day}}
Where:
heb_month
can either be the Hebrew month, like Adar, or it's number, like 12 for Adarheb_day
is the Hebrew day of month
So for example, if you wanted to compute when the next Tu B'shvat falls out on, from the current date:
{{#invoke:Next Occurrence of Hebrew Date|next_occurrence_of_hebrew_date|Shevat|15}}
which returns February 13, 2025
-- Based on public domain code from: http://emr.cs.iit.edu/~reingold/calendar.C local p = {} -- Absolute dates -- "Absolute date" means the number of days elapsed since the Gregorian date -- Sunday, December 31, 1 BC. (Since there was no year 0, the year following -- 1 BC is 1 AD.) Thus the Gregorian date January 1, 1 AD is absolute date -- number 1. -- Gregorian dates function LastDayOfGregorianMonth(month, year) -- Compute the last date of the month for the Gregorian calendar. if month == 2 then if ((((year % 4) == 0) and ((year % 100) ~= 0)) or ((year % 400) == 0)) then return 29; else return 28; end elseif month == 4 or month == 6 or month == 9 or month == 11 then return 30; else return 31; end end GregorianDate = {} GregorianDate.__index = GregorianDate function GregorianDate.create(month, day, year) local gregoriandate = {} -- our new object setmetatable(gregoriandate,GregorianDate) -- make GregorianDate handle lookup -- initialize our object gregoriandate.month = month -- 1 == January, ..., 12 == December gregoriandate.day = day -- 1..LastDayOfGregorianMonth(month, year) gregoriandate.year = year -- return gregoriandate end function GregorianDateFromAbsolute(d) -- Computes the Gregorian date from the absolute date. -- Search forward year by year from approximate year local year = math.floor(d/366); while (d >= AbsoluteFromGregorianDate(GregorianDate.create(1,1,year+1))) do year = year + 1; end -- Search forward month by month from January local month = 1; while (d > AbsoluteFromGregorianDate(GregorianDate.create(month, LastDayOfGregorianMonth(month,year), year))) do month = month + 1; end local day = d - AbsoluteFromGregorianDate(GregorianDate.create(month,1,year)) + 1; return GregorianDate.create(month, day, year) end function AbsoluteFromGregorianDate(gregoriandate) -- Computes the absolute date from the Gregorian date. local N = gregoriandate.day; -- days this month -- days in prior months this year local m = gregoriandate.month - 1; while (m > 0) do N = N + LastDayOfGregorianMonth(m, gregoriandate.year); m = m - 1; end return (N -- days this year + 365 * (gregoriandate.year - 1) -- days in previous years ignoring leap days + math.floor((gregoriandate.year - 1)/4) -- Julian leap days before this year... - math.floor((gregoriandate.year - 1)/100) -- ...minus prior century years... + math.floor((gregoriandate.year - 1)/400)); -- ...plus prior years divisible by 400 end -- Hebrew dates HebrewEpoch = -1373429 -- Absolute date of start of Hebrew calendar function HebrewLeapYear(year) -- True if year is an Hebrew leap year if ((((7 * year) + 1) % 19) < 7) then return 1; else return 0; end end --Last month of Hebrew year. function LastMonthOfHebrewYear(year) if (HebrewLeapYear(year) == 1) then return 13; else return 12; end end function HebrewCalendarElapsedDays(year) -- Number of days elapsed from the Sunday prior to the start of the -- Hebrew calendar to the mean conjunction of Tishri of Hebrew year. local MonthsElapsed = (235 * math.floor((year - 1) / 19)) -- Months in complete cycles so far. + (12 * ((year - 1) % 19)) -- Regular months in this cycle. + math.floor((7 * ((year - 1) % 19) + 1) / 19); -- Leap months this cycle local PartsElapsed = 204 + 793 * (MonthsElapsed % 1080); local HoursElapsed = 5 + 12 * MonthsElapsed + 793 * math.floor(MonthsElapsed / 1080) + math.floor(PartsElapsed / 1080); local ConjunctionDay = 1 + 29 * MonthsElapsed + math.floor(HoursElapsed / 24); local ConjunctionParts = 1080 * (HoursElapsed % 24) + PartsElapsed % 1080; local AlternativeDay = 0; if ((ConjunctionParts >= 19440) -- If new moon is at or after midday, or (((ConjunctionDay % 7) == 2) -- ...or is on a Tuesday... and (ConjunctionParts >= 9924) -- at 9 hours, 204 parts or later... and (HebrewLeapYear(year)) == 0) -- ...of a common year, or (((ConjunctionDay % 7) == 1) -- ...or is on a Monday at... and (ConjunctionParts >= 16789) -- 15 hours, 589 parts or later... and (HebrewLeapYear(year - 1) == 1))) then -- at the end of a leap year -- Then postpone Rosh HaShanah one day AlternativeDay = ConjunctionDay + 1; else AlternativeDay = ConjunctionDay; end if (((AlternativeDay % 7) == 0)-- If Rosh HaShanah would occur on Sunday, or ((AlternativeDay % 7) == 3) -- or Wednesday, or ((AlternativeDay % 7) == 5)) -- or Friday -- Then postpone it one (more) day then return (1+ AlternativeDay); else return AlternativeDay; end end function DaysInHebrewYear(year) -- Number of days in Hebrew year. return ((HebrewCalendarElapsedDays(year + 1)) - (HebrewCalendarElapsedDays(year))); end function LongHeshvan(year) -- True if Heshvan is long in Hebrew year. if ((DaysInHebrewYear(year) % 10) == 5) then return 1; else return 0; end end function ShortKislev(year) -- True if Kislev is short in Hebrew year. if ((DaysInHebrewYear(year) % 10) == 3) then return 1; else return 0; end end function LastDayOfHebrewMonth(month, year) -- Last day of month in Hebrew year. if ((month == 2) or (month == 4) or (month == 6) or ((month == 8) and LongHeshvan(year) == 0) or ((month == 9) and ShortKislev(year) == 1) or (month == 10) or ((month == 12) and (HebrewLeapYear(year) == 0)) or (month == 13)) then return 29; else return 30; end end HebrewDate = {} HebrewDate.__index = HebrewDate function HebrewDate.create(month, day, year) local hebrewdate = {} -- our new object setmetatable(hebrewdate,HebrewDate) -- make HebrewDate handle lookup -- initialize our object hebrewdate.month = month -- 1... hebrewdate.day = day -- 1..LastMonthOfHebrewYear(year) hebrewdate.year = year -- 1..LastDayOfHebrewMonth(month, year) return hebrewdate end function HebrewDateFromAbsolute(d) -- Computes the Hebrew date from the absolute date. local year = math.floor((d + HebrewEpoch) / 366); -- Approximation from below. -- Search forward for year from the approximation. while (d >= AbsoluteFromHebrewDate(HebrewDate.create(7,1,year + 1))) do year = year + 1; end -- Search forward for month from either Tishri or Nisan. local month = 0 if (d < AbsoluteFromHebrewDate(HebrewDate.create(1, 1, year))) then month = 7; -- Start at Tishri else month = 1; -- Start at Nisan end while (d > AbsoluteFromHebrewDate(HebrewDate.create(month, (LastDayOfHebrewMonth(month,year)), year))) do month = month + 1; end -- Calculate the day by subtraction. local day = d - AbsoluteFromHebrewDate(HebrewDate.create(month, 1, year)) + 1; return HebrewDate.create(month, day, year) end function AbsoluteFromHebrewDate(hebrewdate) -- Computes the absolute date of Hebrew date. local DayInYear = hebrewdate.day; -- Days so far this month. if (hebrewdate.month < 7) then -- Before Tishri, so add days in prior months -- this year before and after Nisan. local m = 7; while (m <= (LastMonthOfHebrewYear(hebrewdate.year))) do DayInYear = DayInYear + LastDayOfHebrewMonth(m, hebrewdate.year); m = m + 1; end m = 1; while (m < hebrewdate.month) do DayInYear = DayInYear + LastDayOfHebrewMonth(m, hebrewdate.year); m = m + 1; end else -- Add days in prior months this year local m = 7; while (m < hebrewdate.month) do DayInYear = DayInYear + LastDayOfHebrewMonth(m, hebrewdate.year); m = m + 1; end end return (DayInYear + (HebrewCalendarElapsedDays(hebrewdate.year)-- Days in prior years. + HebrewEpoch)); -- Days elapsed before absolute date 1. end function find_gregorian_for_next_hebrew_date_occurrence(greg_year, greg_month, greg_day, heb_month, heb_day) local greg_absolute = AbsoluteFromGregorianDate(GregorianDate.create(greg_month, greg_day, greg_year)) local hebrew_date = HebrewDateFromAbsolute(greg_absolute) local heb_year = hebrew_date.year -- Check if we already passed that date this year. If we have, increase the year by 1 local this_years_hebrew_absolute = AbsoluteFromHebrewDate(HebrewDate.create(heb_month, heb_day, heb_year)) if (greg_absolute > this_years_hebrew_absolute) then heb_year = heb_year + 1 end -- Certain months only have 29 days. Advance years until we find a year with 30 days that month. if heb_day == 30 then while ((heb_month == 8) and not(LongHeshvan(heb_year))) or ((heb_month == 9) and ShortKislev(heb_year)) or ((heb_month == 12) and (HebrewLeapYear(heb_year) == 0)) do heb_year = heb_year + 1 end end -- The year we're in has the date. Get the absolute and convert it back to a Gregorian date local absolute = AbsoluteFromHebrewDate(HebrewDate.create(heb_month, heb_day, heb_year)) local gregorian = GregorianDateFromAbsolute(absolute) return gregorian end function GregorianMonthToName(monthNumber) if monthNumber == 1 then return "January" elseif monthNumber == 2 then return "February" elseif monthNumber == 3 then return "March" elseif monthNumber == 4 then return "April" elseif monthNumber == 5 then return "May" elseif monthNumber == 6 then return "June" elseif monthNumber == 7 then return "July" elseif monthNumber == 8 then return "August" elseif monthNumber == 9 then return "September" elseif monthNumber == 10 then return "October" elseif monthNumber == 11 then return "November" elseif monthNumber == 12 then return "December" end end function HebrewMonthNameToNumber(month) month = string.lower(month) if month == "nisan" then return 1 elseif month == "iyar" then return 2 elseif month == "sivan" then return 3 elseif month == "tammuz" then return 4 elseif month == "av" then return 5 elseif month == "elul" then return 6 elseif month == "tishrei" then return 7 elseif month == "cheshvan" then return 8 elseif month == "kislev" then return 9 elseif month == "tevet" then return 10 elseif month == "shevat" then return 11 elseif month == "adar" then return 12 else return nil end end function p.next_occurrence_of_hebrew_date_from_date(frame) local greg_year = tonumber(frame.args[1]) local greg_month = tonumber(frame.args[2]) local greg_day = tonumber(frame.args[3]) local heb_month = frame.args[4] local heb_day = tonumber(frame.args[5]) -- Validate some of the parameters: -- heb_month can either be a month name or number heb_month_number = HebrewMonthNameToNumber(heb_month) if heb_month_number then heb_month = heb_month_number else heb_month = tonumber(heb_month) end gregorian = find_gregorian_for_next_hebrew_date_occurrence(greg_year, greg_month, greg_day, heb_month, heb_day) month_name = GregorianMonthToName(gregorian.month) return month_name.." ".. gregorian.day..", "..gregorian.year end function p.next_occurrence_of_hebrew_date(frame) local greg_year = tonumber(os.date("%Y")) local greg_month = tonumber(os.date("%m")) local greg_day = tonumber(os.date("%d")) local heb_month = frame.args[1] local heb_day = tonumber(frame.args[2]) -- Validate some of the parameters: -- heb_month can either be a month name or number heb_month_number = HebrewMonthNameToNumber(heb_month) if heb_month_number then heb_month = heb_month_number else heb_month = tonumber(heb_month) end gregorian = find_gregorian_for_next_hebrew_date_occurrence(greg_year, greg_month, greg_day, heb_month, heb_day) month_name = GregorianMonthToName(gregorian.month) return month_name.." ".. gregorian.day..", "..gregorian.year end return p