Difference between revisions of "Module:Dts"
From Timelines
(self.abbr needs to be run after self:annonval) |
(overhaul parsing for individual date parameters) |
||
Line 1: | Line 1: | ||
− | local | + | local lang = mw.language.getContentLanguage() |
-------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ||
Line 8: | Line 8: | ||
Dts.__index = Dts | Dts.__index = Dts | ||
− | Dts. | + | Dts.months = { |
− | Dts. | + | "January", |
− | + | "February", | |
+ | "March", | ||
+ | "April", | ||
+ | "May", | ||
+ | "June", | ||
+ | "July", | ||
+ | "August", | ||
+ | "September", | ||
+ | "October", | ||
+ | "November", | ||
+ | "December" | ||
+ | } | ||
+ | |||
+ | Dts.monthsAbbr = { | ||
+ | "Jan", | ||
+ | "Feb", | ||
+ | "Mar", | ||
+ | "Apr", | ||
+ | "May", | ||
+ | "Jun", | ||
+ | "Jul", | ||
+ | "Aug", | ||
+ | "Sep", | ||
+ | "Oct", | ||
+ | "Nov", | ||
+ | "Dec" | ||
+ | } | ||
function Dts.new(args) | function Dts.new(args) | ||
Line 16: | Line 42: | ||
self.format = args.format or "mdy" | self.format = args.format or "mdy" | ||
self.abbr = false -- Default | self.abbr = false -- Default | ||
+ | |||
+ | if args[2] or args[3] or args[4] then | ||
+ | -- YMD parameters are specified individually. | ||
+ | if args[1] then | ||
+ | self.year = tonumber(args[1]) | ||
+ | if not self.year then | ||
+ | error(string.format( | ||
+ | "'%s' is not a valid year", | ||
+ | tostring(args[1]) | ||
+ | ), 3) | ||
+ | end | ||
+ | end | ||
+ | if args[2] then | ||
+ | if tonumber(args[2]) then | ||
+ | self.month = tonumber(args[2]) | ||
+ | elseif type(args[2]) == 'string' then | ||
+ | local lower = args[2]:lower() | ||
+ | local function setMonth(months, isAbbr) | ||
+ | for i, month in ipairs(months) do | ||
+ | if month:lower() == lower then | ||
+ | self.month = i | ||
+ | if isAbbr then | ||
+ | self.abbr = true | ||
+ | end | ||
+ | break | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | setMonth(Dts.months) | ||
+ | if not self.month then | ||
+ | setMonth(Dts.monthsAbbr, true) | ||
+ | end | ||
+ | end | ||
+ | if not self.month then | ||
+ | error(string.format( | ||
+ | "'%s' is not a valid month", | ||
+ | tostring(args[2]) | ||
+ | ), 3) | ||
+ | end | ||
+ | end | ||
+ | if args[3] then | ||
+ | self.day = tonumber(args[3]) | ||
+ | if not self.day then | ||
+ | error(string.format( | ||
+ | "'%s' is not a valid day", | ||
+ | tostring(args[3]) | ||
+ | ), 3) | ||
+ | end | ||
+ | end | ||
+ | if args[4] then | ||
+ | local bc = type(args[4]) == 'string' and args[4]:lower() | ||
+ | if bc == 'bc' or bc == 'bce' then | ||
+ | if self.year and self.year > 0 then | ||
+ | self.year = -self.year | ||
+ | end | ||
+ | elseif bc ~= 'ad' or bc ~= 'ce' then | ||
+ | error(string.format( | ||
+ | "'%s' is not a valid era code (expected 'BC', 'BCE', 'AD' or 'CE')", | ||
+ | tostring(args[4]) | ||
+ | ), 3) | ||
+ | end | ||
+ | end | ||
+ | elseif args[1] then | ||
+ | -- args[1] is the entire date that we need to parse. | ||
+ | else | ||
+ | error('no date parameters detected', 3) | ||
+ | end | ||
+ | |||
if args[1] and (not args[2]) then | if args[1] and (not args[2]) then | ||
for _, val in pairs(mw.text.split(args[1],"[%s/-]")) do | for _, val in pairs(mw.text.split(args[1],"[%s/-]")) do | ||
Line 38: | Line 132: | ||
end | end | ||
return self | return self | ||
+ | end | ||
+ | |||
+ | function Dts.formatDate(format, timestamp) | ||
+ | local success, ret = pcall(lang.formatDate, lang, format, timestamp) | ||
+ | if success then | ||
+ | return ret | ||
+ | end | ||
end | end | ||
Revision as of 18:41, 1 July 2015
Documentation for this module may be created at Module:Dts/doc
local lang = mw.language.getContentLanguage() -------------------------------------------------------------------------------- -- Dts class -------------------------------------------------------------------------------- local Dts = {} Dts.__index = Dts Dts.months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" } Dts.monthsAbbr = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } function Dts.new(args) local self = setmetatable({}, Dts) self.format = args.format or "mdy" self.abbr = false -- Default if args[2] or args[3] or args[4] then -- YMD parameters are specified individually. if args[1] then self.year = tonumber(args[1]) if not self.year then error(string.format( "'%s' is not a valid year", tostring(args[1]) ), 3) end end if args[2] then if tonumber(args[2]) then self.month = tonumber(args[2]) elseif type(args[2]) == 'string' then local lower = args[2]:lower() local function setMonth(months, isAbbr) for i, month in ipairs(months) do if month:lower() == lower then self.month = i if isAbbr then self.abbr = true end break end end end setMonth(Dts.months) if not self.month then setMonth(Dts.monthsAbbr, true) end end if not self.month then error(string.format( "'%s' is not a valid month", tostring(args[2]) ), 3) end end if args[3] then self.day = tonumber(args[3]) if not self.day then error(string.format( "'%s' is not a valid day", tostring(args[3]) ), 3) end end if args[4] then local bc = type(args[4]) == 'string' and args[4]:lower() if bc == 'bc' or bc == 'bce' then if self.year and self.year > 0 then self.year = -self.year end elseif bc ~= 'ad' or bc ~= 'ce' then error(string.format( "'%s' is not a valid era code (expected 'BC', 'BCE', 'AD' or 'CE')", tostring(args[4]) ), 3) end end elseif args[1] then -- args[1] is the entire date that we need to parse. else error('no date parameters detected', 3) end if args[1] and (not args[2]) then for _, val in pairs(mw.text.split(args[1],"[%s/-]")) do self:annonval(val, true) end else for key, val in pairs(args) do if tonumber(key) then self:annonval(val) end end end if args.abbr then if args.abbr == "on" then self.abbr=true else self.abbr=false end end if (self.year==0) then --not valid. placeholder for no-year self.year = nil end return self end function Dts.formatDate(format, timestamp) local success, ret = pcall(lang.formatDate, lang, format, timestamp) if success then return ret end end function Dts:setmonth(raw) if not raw then self.month = nil return false end local numbermonth = tonumber(raw) if numbermonth and numbermonth > 0 and numbermonth < 13 then self.month = numbermonth return true end for i, mon in pairs(self.monthsSearch) do if string.find(string.lower(raw),mon) then self.month=i if string.find(string.lower(raw),string.lower(self.months[i])) then self.abbr=false else self.abbr=true end return true end end return false end function Dts:annonval(val, dayfirst) local numberval if val then numberval = tonumber(mw.text.trim(val,"%s%t,")) end if (not val) or (type(val)=="table") or (mw.text.trim(val)=="") then numberval = 0 end if not numberval then if mw.text.trim(string.lower(val)) == "bc" then if (not self.year) then self.year = self.day self.day = nil end if self.year then self.year = 0 - self.year end else if self:setmonth(val,dayfirst) and dayfirst and self.year and (not self.day) and (self.year > 0) and (self.year<31) then self.day = self.year self.year = nil self.format = "dmy" end end return end if self.month and (not self.day) and (numberval < 32) and (numberval > 0) then self.day = numberval return end if self.year and (not self.month) then self.month = numberval return end if (not self.year) then self.year = numberval return end end function Dts:monthName() if (not self.month) or (self.month < 0) or (self.month > 12) then return "" end if self.abbr then return self.monthsAbr[self.month] else return self.months[self.month] end end function Dts:makeSortKey() local year = self.year or os.date("*t").year year = year > 0 and year or -10000 - year return string.format( "%05d-%02d-%02d-%02d%02d", year, self.month or 1, self.day or 1, 0, 0 ) end function Dts:makeDisplay() local ret = {} if self.day then if self.format == "mdy" then ret[#ret + 1] = self:monthName() ret[#ret + 1] = ' ' ret[#ret + 1] = self.day if self.year then ret[#ret + 1] = ',' end else ret[#ret + 1] = self.day ret[#ret + 1] = ' ' ret[#ret + 1] = self:monthName() end elseif self.month then ret[#ret + 1] = self:monthName() end if self.year then if self.month then ret[#ret + 1] = ' ' end ret[#ret + 1] = math.abs(self.year) if self.year < 0 then ret[#ret + 1] = ' BC' end end return table.concat(ret) end function Dts:__tostring() local root = mw.html.create() root :tag('span') :addClass('sortkey') :css('display', 'none') :css('speak', 'none') :wikitext(self:makeSortKey()) :done() :tag('span') :css('white-space', 'nowrap') :wikitext(self:makeDisplay()) return tostring(root) end -------------------------------------------------------------------------------- -- Exports -------------------------------------------------------------------------------- local p = {} function p._main(args) local dts = Dts.new(args) return tostring(dts) end function p.main(frame) local args = getArgs(frame, { wrappers = 'Template:Dts', removeBlanks = false }) return p._main(args) end return p