Module:Easter Explained

local m =

local EasterData = local function formatEasterError(message, ...) if select('#', ...) > 0 then message = string.format(message, ...) end return "

" .. message .. ""end local function loadEasterYear(year) if not year then return false, formatEasterError(EasterData.errorMissingYear) end local result = tonumber(year) if not result or math.floor(result) ~= result then return false, formatEasterError(EasterData.errorInvalidYear, year) end return true, resultend local function loadEasterMethod(method, year) local result = EasterData.defaultMethod if method then result = EasterData.methods[method] if not result then return false, formatEasterError(EasterData.errorInvalidMethod, method) end end if year < 1583 then result = 1 end return true, resultend local function loadEasterOffset(day) if not day then return true, "" end local data = EasterData.relativeDates local offset = tonumber(day) if not offset then offset = data[day] end if not offset or offset ~= math.floor(offset) or offset < EasterData.minimumOffset or offset > EasterData.maximumOffset then return false, formatEasterError(EasterData.errorInvalidOffset, day) end if offset < -1 then return true, string.format(" %d days", offset) elseif offset

-1 then return true, " -1 day" elseif offset

0 then return true, "" elseif offset

1 then return true, " +1 day" else -- if offset > 1 then return true, string.format(" +%d days", offset) endend local function loadEasterFormat(fmt) if fmt

EasterData.noFormat then return true, nil elseif not fmt then return true, EasterData.defaultFormat else return true, fmt endend --local function calculateEasterDate(year, method) if year < 326 or year > 4099 then -- Easter dates are valid for years between 326 and 4099 -- Method 2 would have to support dates in June thereafter return 0, formatEasterError(EasterData.errorYearOutOfRange, year) end if year < 1583 and method ~= 1 then -- Western or Orthodox Easter is valid since 1583 return 0, formatEasterError(EasterData.errorIncorrectMethod, year) end if (year < 1600 or year > 2400) and method ~= 4 then -- The Revised Julian Calendar is not really supported yet return 0, formatEasterError(EasterData.errorYearOutOfRange, year) end -- intermediate result local firstDig = math.floor(year / 100) local remain19 = year % 19 local temp = 0 -- table A to E results local tA = 0 local tB = 0 local tC = 0 local tD = 0 local tE = 0 -- Easter Sunday day local d = 0 -- Julian: if method

1 or method

2 then -- calculate PFM date tA = ((225 - 11 * remain19) % 30) + 21 -- find the next Sunday tB = (tA - 19) % 7 tC = (40 - firstDig) % 7 temp = year % 100 tD = (temp + math.floor(temp / 4)) % 7 tE = ((20 - tB - tC - tD) % 7) + 1 d = tA + tE -- Eastern/Orthodox: if method

2 then -- convert Julian to Gregorian date -- 10 days were skipped in the Gregorian calendar from 5-14 Oct 1582 temp = 10 -- only 1 in every 4 century years are leap years in the Gregorian -- calendar (every century is a leap year in the Julian calendar) if year > 1600 then temp = temp + firstDig - 16 - math.floor((firstDig - 16) / 4) end d = d + temp end -- Gregorian: elseif method

3 or method

4 then -- calculate paschal full moon (PFM) date temp = math.floor((firstDig - 15) / 2) + 202 - 11 * remain19 if firstDig > 26 then temp = temp - 1 end if firstDig > 38 then temp = temp - 1 end if firstDig

21 or firstDig

24 or firstDig

25 or firstDig

33 or firstDig

36 or firstDig

37 then temp = temp - 1 end temp = temp % 30 tA = temp + 21 if temp

29 then tA = tA - 1 end if temp

28 and remain19 > 10 then tA = tA - 1 end -- find the next Sunday tB = (tA - 19) % 7 tC = (40 - firstDig) % 4 if tC

3 then tC = tC + 1 end if tC > 1 then tC = tC + 1 end temp = year % 100 tD = (temp + math.floor(temp / 4)) % 7 tE = ((20 - tB - tC - tD) % 7) + 1 d = tA + tE else -- Unknown method return 0, formatEasterError(EasterData.errorUnknownMethod, method) end -- when the original calculation is converted to the Gregorian calendar, -- Easter Sunday can occur in May or even in June in the distant future if d > 92 then return 6, d - 92 -- June elseif d > 61 then return 5, d - 61 -- May elseif d > 31 then return 4, d - 31 -- April else return 3, d -- March endend local function Easter(args) local ok local year ok, year = loadEasterYear(args[EasterData.argEasterYear]) if not ok then return year end local method ok, method = loadEasterMethod(args[EasterData.argEasterMethod], year) if not ok then return method end local offset ok, offset = loadEasterOffset(args[EasterData.argEasterOffset]) if not ok then return offset end local format ok, format = loadEasterFormat(args[EasterData.argEasterFormat]) if not ok then return format end local month, day = calculateEasterDate(year, method) if month