Module:Calendar

-- \/  | ___   __| |_   _| | ___ _ / ___|__ _| | ___ _ __   __| | __ _ _ __  | |\/| |/ _ \ / _` | | | | |/ _ (_) |   / _` | |/ _ \ '_ \ / _` |/ _` | '__| | |  | | (_) | (_| | |_| | |  __/_| |__| (_| | |  __/ | | | (_| | (_| | |    |_|  |_|\___/ \__,_|\__,_|_|\___(_)\____\__,_|_|\___|_| |_|\__,_|\__,_|_|   Maintainers:
 * Jarekt

local p = {}

-- Convert "Julian day number" (jdn) to a calendar date -- "gregorian" is a 1 for gregorian calendar and 0 for Julian -- based on https://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_day_number function p._jdn2date(jdn, gregorian) local f, e, g, h, year, month, day

f = jdn + 1401 if gregorian>0 then f = f + math.floor((math.floor((4*jdn + 274277) / 146097) * 3) / 4) - 38 end e = 4*f + 3 g = math.floor(math.fmod(e, 1461) / 4) h = 5*g + 2 day  = math.floor(math.fmod (h,153) / 5) + 1 month = math.fmod (math.floor(h/153) + 2, 12) + 1 year = math.floor(e/1461) - 4716 + math.floor((14 - month) / 12) -- If year is less than 1, subtract one to convert from a zero based date system to the -- common era system in which the year -1 (1 B.C.E) is followed by year 1 (1 C.E.). if year < 1 then year = year - 1 end return string.format('%04i-%02i-%02i', year, month, day) end

-- Convert calendar date to "Julian day number" (jdn) -- "gregorian" is a 1 for gregorian calendar and 0 for Julian -- based on https://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_day_number -- explanation based on http://www.cs.utsa.edu/~cs1063/projects/Spring2011/Project1/project1.html function p._date2jdn(ISOdate, gregorian) local year, month, day = ISOdate:match( "(-?%d%d%d%d)-(%d%d)-(%d%d)" ) if not year then return nil elseif tonumber(year) < 0 then -- If year is less than 0, add one to convert from the common era system in which -- the year -1 (1 B.C.E) is followed by year 1 (1 C.E.) to a zero based date system year = year + 1 end local a, b, c, d, y, m	a = math.floor((14-month) / 12) -- will be 1 for January and February, and 0 for other months. y = year + 4800 - a            -- years since year –4800 m = month + 12*a - 3           -- month number where 10 for January, 11 for February, 0 for March, 1 for April c = math.floor((153*m + 2)/5)  -- number of days since March 1 if gregorian>0 then b = math.floor(y/4) - math.floor(y/100) + math.floor(y/400) -- number of leap years since y==0 (year –4800) d = 32045                    -- offset so the result will be 0 for January 1, 4713 BCE else b = math.floor(y/4)          -- number of leap years since y==0 (year –4800) d = 32083                    -- offset so the result will be 0 for January 1, 4713 BCE end return day + c + 365*y + b - d end

-- Convert a date from Gregorian to Julian calendar function p.Gregorian2Julian(frame) local JDN = p._date2jdn(frame.args[1], 1) if JDN then return p._jdn2date(JDN, 0) else return "Error parsing input date: " .. frame.args[1] end end

-- Convert a date from Julian to Gregorian calendar function p.Julian2Gregorian(frame) local JDN = p._date2jdn(frame.args[1], 0) if JDN then return p._jdn2date(JDN, 1) else return "Error parsing input date: " .. frame.args[1] end end

-- Return day of week based on gregorian date. Mon->1, Tue->2, ..., Sun->7 function p.DayOfWeek(frame) local JDN = p._date2jdn(frame.args[1], 1) local day = math.fmod(JDN, 7) + 1 if day then local LUT = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" } return LUT[day] else return "Error parsing input date: " .. frame.args[1] end end

-- Convert calendar date to "Julian day number" (jdn) function p.date2jdn(frame) return p._date2jdn(frame.args[1] or os.date('%F'), frame.args[2] or 1) end

return p