Module:Year in various calendars explained

-- Load dependencies.local getArgs = require('Module:Arguments').getArgslocal numToRoman = require('Module:Roman').mainlocal getOlympiad = require('Module:Ancient Olympiads')._mainlocal getDynasty = require('Module:Ancient Egypt era')._mainlocal getPharaoh = require('Module:Ancient Egypt kings')._mainlocal numToArmenian = require('Module:Armenian').mainlocal getRegnal = require('Module:British regnal year').mainlocal japaneseEra = require('Module:Japanese calendar').era

-- Define constants.local lang = mw.language.getContentLanguagelocal currentYear = tonumber(lang:formatDate('Y'))

---------------------------------------------------------------------- Helper functions--------------------------------------------------------------------

local function isInteger(num) -- Checks if a value is an integer. If so, returns the value converted to a number. -- If not, returns false. num = tonumber(num) if num and math.floor(num)

num and num ~= math.huge then return num else return false endend

local function BCToNum(s) -- Converts strings of the format "n BC" to their corresponding -- numerical values. if type(s) ~= 'string' then return nil end s = mw.ustring.match(mw.ustring.upper(s), '^([1-9]%d*)%s*BC$') if not s then return nil end local num = tonumber(s) num = (num - 1) * -1 return numend

local function numToBC(num) -- For BC years, returns a string with the year name appended with " BC". -- Otherwise returns nil. num = isInteger(num) if not num then return end if num <= 0 then return string.format('%d BC', 1 - num) endend

local function ADToNum(s) -- Converts strings of the format "AD n" -- to their corresponding numerical values. if type(s) ~= 'string' then return nil end s = mw.ustring.match(mw.ustring.upper(s), '^AD%s*([1-9]%d*)$') if not s then return nil end local num = tonumber(s) return numend

local function numToAD(num) -- For AD years up to 100, returns a string with the year name prepended with "AD ". -- Otherwise returns nil. num = isInteger(num) if not num then return end if (num <= 100) then return string.format('AD %d', num) endend

local function formatNegative(s) -- Replaces hyphens in a string with minus signs if the hyphen comes before a number. s = mw.ustring.gsub(s, '%-(%d)', '−%1') return send

---------------------------------------------------------------------- Calendar box class definition--------------------------------------------------------------------

local calendarBox = calendarBox.__index = calendarBox

function calendarBox:new(init) init = type(init)

'table' and init or local obj = local pagename = mw.title.getCurrentTitle.text

-- Set the year. If the year is specified as an argument, use that. -- Otherwise, use the page name if it is valid. If the pagename isn't -- valid, use the current year. local yearNum = isInteger(init.year) local yearBC = BCToNum(init.year) local yearAD = ADToNum(init.year) local pageNum = isInteger(pagename) local pageBC = BCToNum(pagename) local pageAD = ADToNum(pagename) if yearNum then -- First, see if the year parameter is a number. self.year = yearNum elseif yearBC then -- Second, see if the year parameter is a "yyyy BC" string. self.year = yearBC elseif yearAD then -- Third, see if the year parameter is an AD/CE/year string. self.year = yearAD elseif pageNum then -- Fourth, see if the pagename is an integer. self.year = pageNum elseif pageBC then -- Fifth, see if the pagename is a "yyyy BC" string. self.year = pageBC elseif pageAD then -- Sixth, see if the pagename is an AD/CE/year string. self.year = pageAD else self.year = currentYear -- If none of the above apply, use the current year. end

-- Set year text values. self.BCYearName = numToBC(self.year) self.ADYearName = numToAD(self.year) if self.BCYearName then self.yearText = self.BCYearName elseif self.ADYearName then self.yearText = self.ADYearName else self.yearText = tostring(self.year) end

-- Set other fields. self.caption = self.yearText self.footnotes = init.footnotes

return setmetatable(obj,)end

function calendarBox:setCaption(s) -- Sets the calendar box caption. if type(s) ~= 'string' or s

then return end self.caption = send

function calendarBox:addCalendar(obj) -- Adds a calendar or a calendar group. if type(obj) ~= 'table' and type(obj.new) ~= 'function' then return end -- Exit if the object is invalid. self.calendars = self.calendars or table.insert(self.calendars, obj)end

-- Add an alias for adding calendar groups. The function is the same, but it might be confusing for users-- to have to use the name "addCalendar" for a calendar group.calendarBox.addCalendarGroup = calendarBox.addCalendar

function calendarBox:export -- Outputs the calendar box wikitext. local root = mw.html.create('table') -- Export the calendar box headers. root :addClass('infobox vevent') :css('width', '22em') :tag('caption') :css('font-size', '125%') :tag('span') :addClass('summary dtstart') :wikitext(self.caption)

-- Export the calendars and calendar groups. "calendar:export" works for both kinds -- of objects. Some export functions can return nil, so we need to check for that. if type(self.calendars)

'table' then for _, calendar in ipairs(self.calendars) do local calendarText = calendar:export if type(calendarText)

'string' then root:wikitext(calendarText) end end end

-- Add footnotes. if type(self.footnotes)

'string' and self.footnotes ~= then root :tag('tr') :tag('td') :attr('colspan', '2') :wikitext(string.format('%s', self.footnotes)) end

return tostring(root)end

---------------------------------------------------------------------- Calendar group class definition--------------------------------------------------------------------

-- Calendar groups are used to group different calendars together. -- Previously, the template did this by including a table row with-- no year value. By using objects we can do the same thing more-- semantically.

local calendarGroup = calendarGroup.__index = calendarGroup

function calendarGroup:new(init) init = type(init)

'table' and init or local obj =

-- Get the heading and throw an error if it is invalid. obj.heading = init.heading if type(obj.heading) ~= 'string' then error('calendarGroup: no heading detected') end

-- Set the metatable and return the object. self.__index = self return setmetatable(obj,)end

function calendarGroup:addCalendar(calendar) -- Adds a calendar object to the calendar group. self.calendars = self.calendars or if type(calendar)

'table' and type(calendar.getLink)

'function' then table.insert(self.calendars, calendar) endend

function calendarGroup:export -- Exports the calendar group's wikitext. -- Indent and italicise each calendar's link if it exists. for i, calendar in ipairs(self.calendars) do local link = calendar:getLink if type(link)

'string' then self.calendars[i ]:setRawLink(string.format(" - %s", link)) end end -- Create the heading row html and export the calendar objects. local ret = mw.html.create ret :tag('tr') :tag('td') :wikitext(self.heading) :done :tag('td') -- Use a blank tag to make the html look nice. :allDone for _, calendar in ipairs(self.calendars) do ret:wikitext(calendar:export) end return tostring(ret)end

---------------------------------------------------------------------- Calendar class definition--------------------------------------------------------------------

local calendar = calendar.__index = calendarcalendar.type = 'calendar'

function calendar:new local obj = return setmetatable(obj,)end

function calendar:setLink(link, display) -- Sets the calendar's wikilink, with optional display text and italics. if type(link) ~= 'string' or link

then return end display = type(display)

'string' and display ~= and display if display then self.link = string.format('%s', link, display) else self.link = string.format('%s', link) endend

function calendar:setRawLink(s) -- Sets the calendar's wikilink as raw wikitext. if type(s) ~= 'string' or s

then return end self.link = send

function calendar:getLink -- Returns the calendar's link value. return self.linkend

function calendar:setYear(year) -- Sets a single year. Can be passed either a string or a number. -- If passed as a number, it is formatted with minus signs instead of hyphens. -- If passed as a string, no minus-sign formatting occurs; this should be done in the individual calendar definitions. if type(year)

'number' then year = tostring(year) self.year = formatNegative(year) elseif type(year)

'string' then self.year = year endend

function calendar:setYearRange(year1, year2) -- Sets a year range. Must be passed two numbers. if type(year1)

'number' and type(year2)

'number' then local year if year1 < 0 or year2 < 0 then -- Leave a gap for negative years to avoid having a minus sign and a dash right next to each other. year = string.format('%d – %d', year1, year2) year = formatNegative(year) else year = string.format('%d–%d', year1, year2) end self.year = year endend

function calendar:setYearCouple(year1, year2, addtext) -- Same as setYearRange, only with a slash (/) in the middle. Must be passed two numbers. -- Additional text possible, must be defined as follows: addtext = string.format('additional text or link') -- See example in Seleucid era calendar if type(year1)

'number' and type(year2)

'number' then local year if year1 < 0 or year2 < 0 then -- Leave no gap for negative years. year = string.format('%d/%d %s', year1, year2, addtext) year = formatNegative(year) else year = string.format('%d/%d %s', year1, year2, addtext) end self.year = year endend

function calendar:export -- Outputs the calendar wikitext. -- Exit if no link has been specified. local link = self.link if type(link) ~= 'string' or link

then return end

-- If no year has been specified, set the year value to N/A. local year = self.year if type(year) ~= 'string' or year

then year = "N/A" end

-- Build the table row. local ret = mw.html.create ret :tag('tr') :tag('td') :wikitext(link) :done :tag('td') :wikitext(year) :allDone return tostring(ret)end

---------------------------------------------------------------------- Build the box--------------------------------------------------------------------

local function makeCalendarBox(args) -- Initiate the box and get the year values. local init = args local box = calendarBox:new(init) local year = box.year local yearText = box.yearText

-- Set the caption. box:setCaption(box.caption .. ' in various calendars')

---------------------------------------------------------------------- -- Gregorian calendar ----------------------------------------------------------------------

local gregorian = calendar:new gregorian:setLink('Gregorian calendar') -- Get the year link. local gregcal = args.gregcal if type(gregcal)

'string' and gregcal ~= then gregorian.yearLink = string.format('%s', gregcal, yearText) else gregorian.yearLink = yearText end -- Set the year. if year <= 0 then gregorian.romanYear = numToRoman .. ' BC' else gregorian.romanYear = numToRoman end if gregorian.romanYear then gregorian:setYear(string.format(gregorian.yearLink, gregorian.romanYear )) else gregorian:setYear(gregorian.yearLink) end box:addCalendar(gregorian) ---------------------------------------------------------------------- -- French Republican calendar -- displays only in years 1793 - 1805 and 1871 -- This calendar was in use and had defined years only for the short period on display. -- Its importance during these few years is also the reason why it should stay out of the alphabetic order. -- See discussion on talk page. ---------------------------------------------------------------------- if year >= 1793 and year < 1806 or year

1871 then local republican = calendar:new republican:setLink('French Republican calendar') if year <= 1870 then republican:setYearRange(year - 1792, year - 1791) elseif year

1871 then republican:setYear(year - 1792) -- Paris Commune, May end box:addCalendar(republican) end ---------------------------------------------------------------------- -- Ab urbe condita -- Varro's correlation, from 1 AUC ---------------------------------------------------------------------- if year >= -752 then local abUrbe = calendar:new abUrbe:setLink('Ab urbe condita') abUrbe:setYear(year + 753) box:addCalendar(abUrbe) end ---------------------------------------------------------------------- -- Ancient Egypt era -- Displays dynasty between 1549 BC and 30 BC -- Displays pharaoh or king between 752 BC and 30 BC ---------------------------------------------------------------------- if year > -1549 and year <= -29 then local ancEgypt = calendar:new ancEgypt:setLink('Egyptian chronology', 'Ancient Egypt era' ) ancEgypt:setYear(getDynasty(year)) box:addCalendar(ancEgypt) end if year > - 752 and year <= -29 then local ancPharaoh = calendar:new ancPharaoh:setLink('List of pharaohs', '- Pharaoh' ) ancPharaoh:setYear(getPharaoh(year)) box:addCalendar(ancPharaoh) end

---------------------------------------------------------------------- -- Ancient Olympiads -- Currently only the first 194 Olympiads -- May be expanded until 394 AD when data available ---------------------------------------------------------------------- if year >= -1300 and year < 1 then local ancOlympiads = calendar:new ancOlympiads:setLink('Ancient Greek calendar', 'Ancient Greek era' ) ancOlympiads:setYear(getOlympiad(year)) box:addCalendar(ancOlympiads) end

---------------------------------------------------------------------- -- Armenian calendar ----------------------------------------------------------------------

if year > 551 then local armenian = calendar:new armenian:setLink('Armenian calendar') local armenianYear = year - 551 armenian:setYear(string.format('%s
ԹՎ %s', armenianYear, numToArmenian(armenianYear))) box:addCalendar(armenian) end

---------------------------------------------------------------------- -- Assyrian calendar ----------------------------------------------------------------------

local assyrian = calendar:new assyrian:setLink('Assyrian calendar') assyrian:setYear(year + 4750) box:addCalendar(assyrian)

---------------------------------------------------------------------- -- Bahá'í calendar -- displays only after 1843 ---------------------------------------------------------------------- if year >= 1844 then local bahai = calendar:new bahai:setLink("Baháʼí calendar") bahai:setYearRange(year - 1844, year - 1843) box:addCalendar(bahai) end ---------------------------------------------------------------------- -- Balinese saka calendar ---------------------------------------------------------------------- local balinese = calendar:new balinese:setLink('Balinese saka calendar') if year - 76 > 0 then balinese:setYearRange(year - 79, year - 78) end box:addCalendar(balinese)

---------------------------------------------------------------------- -- Bengali calendar ----------------------------------------------------------------------

local bengali = calendar:new bengali:setLink('Bengali calendar') bengali:setYear(year - 593) box:addCalendar(bengali)

---------------------------------------------------------------------- -- Berber calendar ----------------------------------------------------------------------

local berber = calendar:new berber:setLink('Berber calendar') berber:setYear(year + 950) box:addCalendar(berber)

---------------------------------------------------------------------- -- Regnal year ----------------------------------------------------------------------

if year >= 1000 then local regnal = calendar:new local regnalName if year > 1706 then regnalName = 'British' else regnalName = 'English' end regnal:setLink('Regnal years of English and British monarchs', regnalName .. ' Regnal year') regnal:setYear(getRegnal(year)) box:addCalendar(regnal) end

---------------------------------------------------------------------- -- Buddhist calendar ----------------------------------------------------------------------

local buddhist = calendar:new buddhist:setLink('Buddhist calendar') buddhist:setYear(year + 544) box:addCalendar(buddhist)

---------------------------------------------------------------------- -- Burmese calendar ----------------------------------------------------------------------

local burmese = calendar:new burmese:setLink('Burmese calendar') burmese:setYear(year - 638) box:addCalendar(burmese)

---------------------------------------------------------------------- -- Byzantine calendar ----------------------------------------------------------------------

local byzantine = calendar:new byzantine:setLink('Byzantine calendar') byzantine:setYearRange(year + 5508, year + 5509) box:addCalendar(byzantine)

---------------------------------------------------------------------- -- Chinese calendar ----------------------------------------------------------------------

local chinese = calendar:new chinese:setLink('Chinese calendar')

-- Define the information for the "heavenly stems" and "earthly branches" year cycles. -- See Chinese calendar#Cycle of years for information.

local heavenlyStems =

local earthlyBranches =

-- Calculate the cycle numbers from the year. The first sexagenary year corresponds to the previous year's entry -- in Chinese calendar correspondence table, as the Chinese New Year doesn't happen until Jan/Feb in -- Gregorian years. local sexagenaryYear1 = (year - 4) % 60 local sexagenaryYear2 = (year - 3) % 60 local heavenlyNum1 = (sexagenaryYear1 - 1) % 10 + 1 -- amod, since lua arrays are 1-indexed local heavenlyNum2 = (sexagenaryYear2 - 1) % 10 + 1 local earthlyNum1 = (sexagenaryYear1 - 1) % 12 + 1 local earthlyNum2 = (sexagenaryYear2 - 1) % 12 + 1

-- Get the data tables for each permutation. local heavenlyTable1 = heavenlyStems[heavenlyNum1 ] local heavenlyTable2 = heavenlyStems[heavenlyNum2 ] local earthlyTable1 = earthlyBranches[earthlyNum1 ] local earthlyTable2 = earthlyBranches[earthlyNum2 ]

-- Work out the continously-numbered year. (See Chinese calendar#Continuously numbered years.) local year1 = year + 2697 local year2 = year + 2698 local year1Alt = year1 - 207 local year2Alt = year2 - 207

-- Format any negative numbers. year1 = formatNegative(tostring(year1)) year2 = formatNegative(tostring(year2)) year1Alt = formatNegative(tostring(year1Alt)) year2Alt = formatNegative(tostring(year2Alt))

-- Return all of that data in a (hopefully) reader-friendly format. chinese:setYear(string.format([=[[[Sexagenary cycle|%s%s]]年 (%s %s)
%s or %s
    — to —
%s%s年 (%s %s)
%s or %s]=], heavenlyTable1[1 ], earthlyTable1[1 ], heavenlyTable1[2 ], earthlyTable1[2 ], year1, year1Alt, heavenlyTable2[1 ], earthlyTable2[1 ], heavenlyTable2[2 ], earthlyTable2[2 ], year2, year2Alt ))

box:addCalendar(chinese)

---------------------------------------------------------------------- -- Coptic calendar ----------------------------------------------------------------------

local coptic = calendar:new coptic:setLink('Coptic calendar') coptic:setYearRange(year - 284, year - 283) box:addCalendar(coptic)

---------------------------------------------------------------------- -- Discordian calendar ----------------------------------------------------------------------

local discordian = calendar:new discordian:setLink('Discordian calendar') discordian:setYear(year + 1166) box:addCalendar(discordian)

---------------------------------------------------------------------- -- Ethiopian calendar ----------------------------------------------------------------------

local ethiopian = calendar:new ethiopian:setLink('Ethiopian calendar') ethiopian:setYearRange(year - 8, year - 7) box:addCalendar(ethiopian)

---------------------------------------------------------------------- -- Hebrew calendar ----------------------------------------------------------------------

local hebrew = calendar:new hebrew:setLink('Hebrew calendar') hebrew:setYearRange(year + 3760, year + 3761) box:addCalendar(hebrew)

---------------------------------------------------------------------- -- Hindu calendars ----------------------------------------------------------------------

local hindu = calendarGroup:new

-- Vikram Samvat

local vikramSamvat = calendar:new vikramSamvat:setLink('Vikram Samvat') vikramSamvat:setYearRange(year + 56, year + 57) hindu:addCalendar(vikramSamvat)

-- Shaka Samvat

local shakaSamvat = calendar:new shakaSamvat:setLink('Indian national calendar', 'Shaka Samvat') if year >= 78 then shakaSamvat:setYearRange(year - 79, year - 78) end hindu:addCalendar(shakaSamvat)

-- Kali Yuga

local kaliYuga = calendar:new kaliYuga:setLink('Kali Yuga') -- use italics kaliYuga:setYearRange(year + 3100, year + 3101) hindu:addCalendar(kaliYuga)

box:addCalendarGroup(hindu)

---------------------------------------------------------------------- -- Holocene calendar ----------------------------------------------------------------------

local holocene = calendar:new holocene:setLink('Holocene calendar') holocene:setYear(year + 10000) box:addCalendar(holocene)

---------------------------------------------------------------------- -- Igbo calendar ----------------------------------------------------------------------

-- In the old template this was a calendar group with just one calendar; intentionally adding this as a single -- calendar here, as the previous behaviour looked like a mistake. if year >= 1000 then local igbo = calendar:new igbo:setLink('Igbo calendar') igbo:setYearRange(year - 1000, year - 999) box:addCalendar(igbo) end

---------------------------------------------------------------------- -- Iranian calendar ----------------------------------------------------------------------

local iranian = calendar:new iranian:setLink('Iranian calendars', 'Iranian calendar') if year - 621 > 0 then iranian:setYearRange(year - 622, year - 621) else iranian:setYear(string.format('%d BP – %d BP', 622 - year, 621 - year)) end box:addCalendar(iranian)

---------------------------------------------------------------------- -- Islamic calendar ----------------------------------------------------------------------

local islamic = calendar:new islamic:setLink('Islamic calendar') local islamicMult = 1.030684 -- the factor to multiply by local islamicSub = 621.5643 -- the factor to subtract by if year - 621 > 0 then local year1 = math.floor(islamicMult * (year - islamicSub)) local year2 = math.floor(islamicMult * (year - islamicSub + 1)) islamic:setYearRange(year1, year2) else local year1 = math.ceil(-islamicMult * (year - islamicSub)) local year2 = math.ceil(-islamicMult * (year - islamicSub + 1)) islamic:setYear(string.format('%d BH – %d BH', year1, year2)) end box:addCalendar(islamic)

---------------------------------------------------------------------- -- Japanese calendar -- starting 600 ---------------------------------------------------------------------- if year >= 600 then local japanese = calendar:new japanese:setLink('Japanese calendar')

japanese.thisEra = japaneseEra:new if japanese.thisEra then local japaneseYearText = japanese.oldEra = japanese.thisEra:getOldEra if japanese.oldEra and japanese.oldEra.eraYear and japanese.thisEra.article ~= japanese.oldEra.article then japanese.oldText = string.format('%s %d', japanese.oldEra.link, japanese.oldEra.eraYear) table.insert(japaneseYearText, japanese.oldText) table.insert(japaneseYearText, ' / ') end if japanese.thisEra.eraYear then table.insert(japaneseYearText, string.format('%s %d', japanese.thisEra.link, japanese.thisEra.eraYear)) end table.insert(japaneseYearText, string.format('
(%s%s年)', japanese.thisEra.kanji, japanese.thisEra.eraYearKanji)) japanese:setYear(table.concat(japaneseYearText)) end

box:addCalendar(japanese) end

---------------------------------------------------------------------- -- Javanese calendar ----------------------------------------------------------------------

local javanese = calendar:new javanese:setLink('Javanese calendar') local javaneseMult = 1.030684 -- the factor to multiply by local javaneseSub = 124.9 -- the factor to subtract by if year - 124 > 0 then local year1 = math.floor(javaneseMult * (year - javaneseSub)) local year2 = math.floor(javaneseMult * (year - javaneseSub + 1)) javanese:setYearRange(year1, year2) else local year1 = math.ceil(-javaneseMult * (year - javaneseSub)) local year2 = math.ceil(-javaneseMult * (year - javaneseSub + 1)) end box:addCalendar(javanese) ---------------------------------------------------------------------- -- Juche calendar -- displays only after 1910 ----------------------------------------------------------------------

if year >= 1910 then local juche = calendar:new juche:setLink('Juche calendar') if year > 1911 then juche:setYear(year - 1911) end box:addCalendar(juche) end

---------------------------------------------------------------------- -- Julian calendar ----------------------------------------------------------------------

local julian = calendar:new julian:setLink('Julian calendar')

if year >= -45 and year < 1582 then julian:setYear(gregorian.year) elseif year >= 1582 then local diff = math.floor(year/100-2) - math.floor(year/400) if year % 100

0 and year % 400 ~= 0 then julian:setYear('Gregorian minus ' .. diff-1 .. ' or ' .. diff .. ' days') else julian:setYear('Gregorian minus ' .. diff .. ' days') end end

box:addCalendar(julian)

---------------------------------------------------------------------- -- Korean calendar ----------------------------------------------------------------------

local korean = calendar:new korean:setLink('Korean calendar') korean:setYear(year + 2333) box:addCalendar(korean)

---------------------------------------------------------------------- -- Minguo calendar ----------------------------------------------------------------------

local minguo = calendar:new minguo:setLink('Minguo calendar') if year > 1949 then local minguoYear = year - 1911 minguo:setYear(string.format('ROC %d
民國%d年', minguoYear, minguoYear)) elseif year > 1911 then local minguoYear = year - 1911 minguo:setYear(string.format('ROC %d
民國%d年', minguoYear, minguoYear)) else local minguoYear = 1911 - year + 1 minguo:setYear(string.format('%d before ROC
民前%d年', minguoYear, minguoYear)) end box:addCalendar(minguo) ---------------------------------------------------------------------- -- Nanakshahi calendar ----------------------------------------------------------------------

local nanakshahi = calendar:new nanakshahi:setLink('Nanakshahi calendar') nanakshahi:setYear(year - 1468) box:addCalendar(nanakshahi) ---------------------------------------------------------------------- -- Seleucid era -- displays from 312 BC until 1200 AD ---------------------------------------------------------------------- if year >= -311 and year < 1200 then local seleucid = calendar:new seleucid:setLink('Seleucid era') local addtext = string.format('AG') seleucid:setYearCouple(year + 311, year + 312, addtext) box:addCalendar(seleucid) end

---------------------------------------------------------------------- -- Thai solar calendar ----------------------------------------------------------------------

local thai = calendar:new thai:setLink('Thai solar calendar') if year >= 1941 then thai:setYear(year + 543) else -- if year >= 1912 or year <= 1887 -- year started in March/April thai:setYearRange(year + 542, year + 543) -- else -- Rattanakosin Era, 1888?-1912 -- thai:setYear(string.format('%d  – %d (Rattanakosin Era)', year - 1782, year - 1781)) end box:addCalendar(thai)

---------------------------------------------------------------------- -- Tibetan calendar ----------------------------------------------------------------------

local tibetan = calendar:new tibetan:setLink('Tibetan calendar')

-- Define the information for the "heavenly stems" and "earthly branches" year cycles. -- See Tibetan calendar#Years for information.

local heavenlyStems =

local earthlyBranches =

-- Calculate the cycle numbers from the year. The first sexagenary year corresponds to the previous year's entry -- in Tibetan calendar correspondence table, as the Tibetan New Year doesn't happen until Feb/Mar in -- Gregorian years. local sexagenaryYear1 = (year - 4) % 60 local sexagenaryYear2 = (year - 3) % 60 local heavenlyNum1 = (sexagenaryYear1 - 1) % 10 + 1 -- amod, since lua arrays are 1-indexed local heavenlyNum2 = (sexagenaryYear2 - 1) % 10 + 1 local earthlyNum1 = (sexagenaryYear1 - 1) % 12 + 1 local earthlyNum2 = (sexagenaryYear2 - 1) % 12 + 1

-- Get the data tables for each permutation. local heavenlyTable1 = heavenlyStems[heavenlyNum1 ] local heavenlyTable2 = heavenlyStems[heavenlyNum2 ] local earthlyTable1 = earthlyBranches[earthlyNum1 ] local earthlyTable2 = earthlyBranches[earthlyNum2 ]

-- Work out the continously-numbered year. (See Tibetan calendar#Years with cardinal numbers.) local year1 = year + 126 local year2 = year + 127 local year1Alt1 = year1 - 381 local year1Alt2 = year1 - 1153 local year2Alt1 = year2 - 381 local year2Alt2 = year2 - 1153

-- Format any negative numbers. year1 = formatNegative(tostring(year1)) year2 = formatNegative(tostring(year2)) year1Alt1 = formatNegative(tostring(year1Alt1)) year1Alt2 = formatNegative(tostring(year1Alt2)) year2Alt1 = formatNegative(tostring(year2Alt1)) year2Alt2 = formatNegative(tostring(year2Alt2))

-- Return all of that data in a (hopefully) reader-friendly format. tibetan:setYear(string.format([=[%s%s年<br />(%s-%s)<br />%s or %s or %s<br />&nbsp;&nbsp;&nbsp;&nbsp;''—&nbsp;to&nbsp;—''<br />%s%s年<br />(%s-%s)<br />%s or %s or %s]=], heavenlyTable1[1 ], earthlyTable1[1 ], heavenlyTable1[2 ], earthlyTable1[2 ], year1, year1Alt1, year1Alt2, heavenlyTable2[1 ], earthlyTable2[1 ], heavenlyTable2[2 ], earthlyTable2[2 ], year2, year2Alt1, year2Alt2 ))

box:addCalendar(tibetan)

---------------------------------------------------------------------- -- Unix time ----------------------------------------------------------------------

local unix = calendar:new

local function getUnixTime(year) if year < 1970 then return end local noError, unixTime = pcall(lang.formatDate, lang, 'U', '1 Jan ' .. tostring(year)) if not noError or noError and not unixTime then return end unixTime = tonumber(unixTime) if unixTime and unixTime >= 0 then return unixTime - 1 end end unix.thisYear = getUnixTime(year) unix.nextYear = getUnixTime(year + 1) if unix.thisYear and unix.nextYear then unix:setLink('Unix time') unix:setYear((unix.thisYear + 1) .. " – " .. unix.nextYear) end

box:addCalendar(unix)

return box:exportend

---------------------------------------------------------------------- Process arguments from #invoke--------------------------------------------------------------------

local p =

function p.main(frame) -- Process the arguments and pass them to the box-building function. local args = getArgs(frame) -- Pass year argument with 'year' parameter or without any name but first argument args.year = args.year or args[1] return makeCalendarBox(args)end

return p