Module:Next Occurrence of Hebrew Date

{{#invoke:Next Occurrence of Hebrew Date|next_occurrence_of_hebrew_date_from_date | greg_year | greg_month | greg_day | heb_month | heb_day}} Where:

Module:Next Occurrence of Hebrew Date

-- 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

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.