请输入您要查询的百科知识:

 

词条 Module:Dts
释义

local yesno = require('Module:Yesno')

local lang = mw.language.getContentLanguage()

local N_YEAR_DIGITS = 12

local MAX_YEAR = 10^N_YEAR_DIGITS - 1


-- 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._makeMonthSearch(t)

local ret = {}

for i, month in ipairs(t) do

ret[month:lower()] = i

end

return ret

end

Dts.monthSearch = Dts._makeMonthSearch(Dts.months)

Dts.monthSearchAbbr = Dts._makeMonthSearch(Dts.monthsAbbr)

Dts.monthSearchAbbr['sept'] = 9 -- Allow "Sept" to match September

Dts.formats = {

dmy = true,

mdy = true,

dm = true,

md = true,

my = true,

y = true,

m = true,

d = true,

hide = true

}

function Dts.new(args)

local self = setmetatable({}, Dts)

-- Parse date parameters.

-- In this step we also record whether the date was in DMY or YMD format,

-- and whether the month name was abbreviated.

if args[2] or args[3] or args[4] then

self:parseDateParts(args[1], args[2], args[3], args[4])

elseif args[1] then

self:parseDate(args[1])

end

-- Raise an error on invalid values

if self.year then

if self.year == 0 then

error('years cannot be zero', 0)

elseif self.year < -MAX_YEAR then

error(string.format(

'years cannot be less than %s',

lang:formatNum(-MAX_YEAR)

), 0)

elseif self.year > MAX_YEAR then

error(string.format(

'years cannot be greater than %s',

lang:formatNum(MAX_YEAR)

), 0)

elseif math.floor(self.year) ~= self.year then

error('years must be an integer', 0)

end

end

if self.month and (

self.month < 1

or self.month > 12

or math.floor(self.month) ~= self.month

) then

error('months must be an integer between 1 and 12', 0)

end

if self.day and (

self.day < 1

or self.day > 31

or math.floor(self.day) ~= self.day

) then

error('days must be an integer between 1 and 31', 0)

end

-- Set month abbreviation behaviour, i.e. whether we are outputting

-- "January" or "Jan".

if args.abbr then

self.isAbbreviated = args.abbr == 'on' or yesno(args.abbr) or false

else

self.isAbbreviated = self.isAbbreviated or false

end

-- Set the format string

if args.format then

self.format = args.format

else

self.format = self.format or 'mdy'

end

if not Dts.formats[self.format] then

error(string.format(

"'%s' is not a valid format",

tostring(self.format)

), 0)

end

-- Set addkey. This adds a value at the end of the sort key, allowing users

-- to manually distinguish between identical dates.

if args.addkey then

self.addkey = tonumber(args.addkey)

if not self.addkey or

self.addkey < 0 or

self.addkey > 9999 or

math.floor(self.addkey) ~= self.addkey

then

error("the 'addkey' parameter must be an integer between 0 and 9999", 0)

end

end

-- Set whether the displayed date is allowed to wrap or not.

self.isWrapping = args.nowrap == 'off' or yesno(args.nowrap) == false

return self

end

function Dts:hasDate()

return (self.year or self.month or self.day) ~= nil

end

-- Find the month number for a month name, and set the isAbbreviated flag as-- appropriate.

function Dts:parseMonthName(s)

s = s:lower()

local month = Dts.monthSearch[s]

if month then

return month

else

month = Dts.monthSearchAbbr[s]

if month then

self.isAbbreviated = true

return month

end

end

return nil

end

-- Parses separate parameters for year, month, day, and era.

function Dts:parseDateParts(year, month, day, bc)

if year then

self.year = tonumber(year)

if not self.year then

error(string.format(

"'%s' is not a valid year",

tostring(year)

), 0)

end

end

if month then

if tonumber(month) then

self.month = tonumber(month)

elseif type(month) == 'string' then

self.month = self:parseMonthName(month)

end

if not self.month then

error(string.format(

"'%s' is not a valid month",

tostring(month)

), 0)

end

end

if day then

self.day = tonumber(day)

if not self.day then

error(string.format(

"'%s' is not a valid day",

tostring(day)

), 0)

end

end

if bc then

local bcLower = type(bc) == 'string' and bc:lower()

if bcLower == 'bc' or bcLower == 'bce' then

if self.year and self.year > 0 then

self.year = -self.year

end

elseif bcLower ~= 'ad' and bcLower ~= 'ce' then

error(string.format(

"'%s' is not a valid era code (expected 'BC', 'BCE', 'AD' or 'CE')",

tostring(bc)

), 0)

end

end

end

-- This method parses date strings. This is a poor man's alternative to-- mw.language:formatDate, but it ends up being easier for us to parse the date-- here than to use mw.language:formatDate and then try to figure out after the-- fact whether the month was abbreviated and whether we were DMY or MDY.

function Dts:parseDate(date)

-- Generic error message.

local function dateError()

error(string.format(

"'%s' is an invalid date",

date

), 0)

end

local function parseDayOrMonth(s)

if s:find('^%d%d?$') then

return tonumber(s)

end

end

local function parseYear(s)

if s:find('^%d%d%d%d?$') then

return tonumber(s)

end

end

-- Deal with year-only dates first, as they can have hyphens in, and later

-- we need to split the string by all non-word characters, including

-- hyphens. Also, we don't need to restrict years to 3 or 4 digits, as on

-- their own they can't be confused as a day or a month number.

self.year = tonumber(date)

if self.year then

return

end

-- Split the string using non-word characters as boundaries.

date = tostring(date)

local parts = mw.text.split(date, '%W+')

local nParts = #parts

if parts[1] == or parts[nParts] == or nParts > 3 then

-- We are parsing a maximum of three elements, so raise an error if we

-- have more. If the first or last elements were blank, then the start

-- or end of the string was a non-word character, which we will also

-- treat as an error.

dateError()

elseif nParts < 1 then

-- If we have less than one element, then something has gone horribly

-- wrong.

error(string.format(

"an unknown error occurred while parsing the date '%s'",

date

), 0)

end

if nParts == 1 then

-- This can be either a month name or a year.

self.month = self:parseMonthName(parts[1])

if not self.month then

self.year = parseYear(parts[1])

if not self.year then

dateError()

end

end

elseif nParts == 2 then

-- This can be any of the following formats:

-- DD Month

-- Month DD

-- Month YYYY

-- YYYY-MM

self.month = self:parseMonthName(parts[1])

if self.month then

-- This is either Month DD or Month YYYY.

self.year = parseYear(parts[2])

if not self.year then

-- This is Month DD.

self.format = 'mdy'

self.day = parseDayOrMonth(parts[2])

if not self.day then

dateError()

end

end

else

self.month = self:parseMonthName(parts[2])

if self.month then

-- This is DD Month.

self.format = 'dmy'

self.day = parseDayOrMonth(parts[1])

if not self.day then

dateError()

end

else

-- This is YYYY-MM.

self.year = parseYear(parts[1])

self.month = parseDayOrMonth(parts[2])

if not self.year or not self.month then

dateError()

end

end

end

elseif nParts == 3 then

-- This can be any of the following formats:

-- DD Month YYYY

-- Month DD, YYYY

-- YYYY-MM-DD

-- DD-MM-YYYY

self.month = self:parseMonthName(parts[1])

if self.month then

-- This is Month DD, YYYY.

self.format = 'mdy'

self.day = parseDayOrMonth(parts[2])

self.year = parseYear(parts[3])

if not self.day or not self.year then

dateError()

end

else

self.day = parseDayOrMonth(parts[1])

if self.day then

self.month = self:parseMonthName(parts[2])

if self.month then

-- This is DD Month YYYY.

self.format = 'dmy'

self.year = parseYear(parts[3])

if not self.year then

dateError()

end

else

-- This is DD-MM-YYYY.

self.format = 'dmy'

self.month = parseDayOrMonth(parts[2])

self.year = parseYear(parts[3])

if not self.month or not self.year then

dateError()

end

end

else

-- This is YYYY-MM-DD

self.year = parseYear(parts[1])

self.month = parseDayOrMonth(parts[2])

self.day = parseDayOrMonth(parts[3])

if not self.year or not self.month or not self.day then

dateError()

end

end

end

end

end

function Dts:makeSortKey()

local year, month, day

local nYearDigits = N_YEAR_DIGITS

if self:hasDate() then

year = self.year or os.date("*t").year

if year < 0 then

year = -MAX_YEAR - 1 - year

nYearDigits = nYearDigits + 1 -- For the minus sign

end

month = self.month or 1

day = self.day or 1

else

-- Blank {{dts}} transclusions should sort last.

year = MAX_YEAR

month = 99

day = 99

end

return string.format(

'%0' .. nYearDigits .. 'd-%02d-%02d-%04d',

year, month, day, self.addkey or 0

)

end

function Dts:getMonthName()

if not self.month then

return

end

if self.isAbbreviated then

return self.monthsAbbr[self.month]

else

return self.months[self.month]

end

end

function Dts:makeDisplay()

if self.format == 'hide' then

return

end

local hasYear = self.year and self.format:find('y')

local hasMonth = self.month and self.format:find('m')

local hasDay = self.day and self.format:find('d')

local isMonthFirst = self.format:find('md')

local ret = {}

if hasDay and hasMonth and isMonthFirst then

ret[#ret + 1] = self:getMonthName()

ret[#ret + 1] = ' '

ret[#ret + 1] = self.day

if hasYear then

ret[#ret + 1] = ','

end

elseif hasDay and hasMonth then

ret[#ret + 1] = self.day

ret[#ret + 1] = ' '

ret[#ret + 1] = self:getMonthName()

elseif hasDay then

ret[#ret + 1] = self.day

elseif hasMonth then

ret[#ret + 1] = self:getMonthName()

end

if hasYear then

if hasDay or hasMonth then

ret[#ret + 1] = ' '

end

local displayYear = math.abs(self.year)

if displayYear > 9999 then

displayYear = lang:formatNum(displayYear)

else

displayYear = tostring(displayYear)

end

ret[#ret + 1] = displayYear

if self.year < 0 then

ret[#ret + 1] = ' BC'

end

end

return table.concat(ret)

end

function Dts:__tostring()

local root = mw.html.create()

local span = root:tag('span')

:attr('data-sort-value', self:makeSortKey())

-- Display

if self:hasDate() and self.format ~= 'hide' then

span:wikitext(self:makeDisplay())

if not self.isWrapping then

span:css('white-space', 'nowrap')

end

end

return tostring(root)

end


-- Exports

local p = {}

function p._exportClasses()

return {

Dts = Dts

}

end

function p._main(args)

local success, ret = pcall(function ()

local dts = Dts.new(args)

return tostring(dts)

end)

if success then

return ret

else

ret = string.format(

'Error in Dts: %s',

ret

)

if mw.title.getCurrentTitle().namespace == 0 then

-- Only categorise in the main namespace

ret = ret ..

end

return ret

end

end

function p.main(frame)

local args = require('Module:Arguments').getArgs(frame, {

wrappers = 'Template:Dts',

})

return p._main(args)

end

return p

1 : Dts templates with errors

随便看

 

开放百科全书收录14589846条英语、德语、日语等多语种百科知识,基本涵盖了大多数领域的百科知识,是一部内容自由、开放的电子版国际百科全书。

 

Copyright © 2023 OENC.NET All Rights Reserved
京ICP备2021023879号 更新时间:2024/9/20 20:52:10