模組:Date table sorting

可在模組:Date table sorting/doc建立此模組的說明文件

local yesno = require('Module:Yesno')local lang = mw.language.getContentLanguage()local N_YEAR_DIGITS = 12local MAX_YEAR = 10^N_YEAR_DIGITS - 1---------------------------------------------------------------------------------- Dts class--------------------------------------------------------------------------------local Dts = {}function Dts.GetErrMsgFromOther (frame, args) local msg = ''local args = {}if frame == mw.getCurrentFrame() thenmsg = frame.args[1] or frame.args['1'] or ''args[1] = frame.args[2] or frame.args['2'] or ''args[2] = frame.args[3] or frame.args['3'] or ''args[3] = frame.args[4] or frame.args['4'] or ''args['cat'] = 0elsereturn Dts.errmsg (frame, args)endreturn Dts.errmsg (msg, args)endfunction Dts.errmsg (msg, args) msg = msg or ''args = args or {}local needcat = args['cat'] or 1local function arg (x)if args[x] thenreturn args[x]endreturn ''endlocal msglist = {['error'] = '<strong class="error">[[Module:Date table sorting]]錯誤:%s</strong>',['valid-err'] = '解析日期格式「%s」時出現未知錯誤。',['valid-year'] = '給出的年份「%s」年不合理。',['valid-month'] = '給出的月份「%s」月不合理。',['valid-day'] = '給出的日「%s」日不合理。',['valid-bc'] = '給出的西元前後判斷值「%s」不合理(僅能使用「BC」, 「BCE」, 「AD」 或「CE」)。',['valid-date'] = '給出的日期「%s」不合理。',['valid-args-addkey'] = '參數<code>addkey</code>的值「%s」不合理。',['year-zero'] = '年份不得為零。',['year-min'] = '給出的年份「%s年」低於最小值%s年。',['year-max'] = '給出的年份「%s年」超出最大值%s年。',['year-integer'] = '給出的年份「%s年」不是整數。',['unknown-month'] = '月份只有1月到12月,沒有「第%s月」!',['unknown-day-31'] = '%s月只有31天,沒有「第%s天」!',['unknown-day-30'] = '%s月只有30天,沒有「第%s天」!',['unknown-day-Feb'] = '%s年2月只有%s天,沒有「第%s天」!',['unknown-format'] = '無法識別格式「%s」。',['args-addkey'] = '參數<code>addkey</code>的值應介於0到9999之間。'}return string.format((msglist[msg] or ''), (args[1] or ''), (args[2] or ''), (args[3] or ''), (args[4] or ''))endDts.__index = DtsDts.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) doret[month:lower()] = iendreturn retendDts.monthSearch = Dts._makeMonthSearch(Dts.months)Dts.monthSearchAbbr = Dts._makeMonthSearch(Dts.monthsAbbr)Dts.monthSearchAbbr['sept'] = 9 -- Allow "Sept" to match SeptemberDts.formats = {ymd = true,dmy = true,mdy = true,ym = 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] thenself:parseDateParts(args[1], args[2], args[3], args[4])elseif args[1] thenself:parseDate(args[1])end-- Raise an error on invalid valuesif self.year thenif self.year == 0 thenerror(self.errmsg('year-zero') , 0)elseif self.year < -MAX_YEAR thenerror(self.errmsg('year-min', {self.year, lang:formatNum(-MAX_YEAR)}), 0)elseif self.year > MAX_YEAR thenerror(self.errmsg('year-max', {self.year, lang:formatNum(MAX_YEAR)}), 0)elseif math.floor(self.year) ~= self.year thenerror(self.errmsg('year-integer', {self.year}), 0)endendif self.month and (self.month < 1or self.month > 12or math.floor(self.month) ~= self.month) thenerror(self.errmsg('unknown-month', {self.month}), 0)endif self.day thenif ((self.month == 1) or (self.month == 3)or (self.month == 5)or (self.month == 7)or (self.month == 8)or (self.month == 10)or (self.month == 12)) and (self.day > 31) thenerror(self.errmsg('unknown-day-31', {self.month, self.day}), 0)elseif ((self.month == 4) or (self.month == 6)or (self.month == 9)or (self.month == 11)) and (self.day > 30) thenerror(self.errmsg('unknown-day-30', {self.month, self.day}), 0)elseif (self.month == 2) and (self.day > 29) and (self.year % 400 == 0 or self.year % 4 == 0 and self.year % 100 ~= 0) thenerror(self.errmsg('unknown-day-Feb', {self.year, 29, self.day}), 0)elseif (self.month == 2) and (self.day > 28) and not (self.year % 400 == 0 or self.year % 4 == 0 and self.year % 100 ~= 0) thenerror(self.errmsg('unknown-day-Feb', {self.year, 28, self.day}), 0)endend--]=]-- Set debug modeif args.debug thenself.isdebug = args.debugend-- Set the format stringif args.format thenself.format = args.formatelseself.format = self.format or 'ymd'endif not Dts.formats[self.format] thenerror(self.errmsg('unknown-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 thenself.addkey = tonumber(args.addkey)if not self.addkey ormath.floor(self.addkey) ~= self.addkeythenerror(self.errmsg('valid-args-addkey', {args.addkey}), 0)elseif self.addkey < 0 or self.addkey > 9999 thenerror(self.errmsg('args-addkey'), 0)endend-- Set whether the displayed date is allowed to wrap or not.self.isWrapping = args.nowrap == 'off' or yesno(args.nowrap) == false-- Set whether the abbreviated or not.self.isAbbreviated = args.abbr == 'on' or yesno(args.abbr) == true-- Check for deprecated parameters.if args.link thenself.hasDeprecatedParameters = trueendreturn selfendfunction Dts:hasDate()return (self.year or self.month or self.day) ~= nilend-- 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 thenreturn monthelsemonth = Dts.monthSearchAbbr[s]if month thenself.isAbbreviated = truereturn monthendendreturn nilend-- Parses separate parameters for year, month, day, and era.function Dts:parseDateParts(year, month, day, bc)if year thenself.year = tonumber(year)if not self.year thenerror(self.errmsg('valid-year', {tostring(year)}), 0)endendif month thenif tonumber(month) thenself.month = tonumber(month)elseif type(month) == 'string' thenself.month = self:parseMonthName(month)endif not self.month thenerror(self.errmsg('valid-month', {tostring(month)}), 0)endendif day thenself.day = tonumber(day)if not self.day thenerror(self.errmsg('valid-day', {tostring(day)}))endendif bc thenlocal bcLower = type(bc) == 'string' and bc:lower()if bcLower == 'bc' or bcLower == 'bce' thenif self.year and self.year > 0 thenself.year = -self.yearendelseif bcLower ~= 'ad' and bcLower ~= 'ce' thenerror(self.errmsg('valid-bc', {tostring(bc)}), 0)endendend-- 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(self.errmsg('valid-date', {tostring(date)}), 0)endlocal function parseDayOrMonth(s)if s:find('^%d%d?$') thenreturn tonumber(s)endendlocal function parseMonth(s)if s:find('^%d%d?$') and tonumber(s) >=1 and tonumber(s) <= 12 thenreturn tonumber(s)endendlocal function parseDay(s)if self.month thenlastday = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}if s:find('^%d%d?$') and tonumber(s) >=1 and tonumber(s) <= lastday[self.month] thenreturn tonumber(s)endendendlocal function parseYear(s)if s:find('^%d%d?%d?%d?$') thenreturn tonumber(s)endend-- 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 thenreturnend-- Split the string using non-word characters as boundaries.date = tostring(date)local parts = mw.text.split(date, '%W+')local nParts = #partsif 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(self.errmsg('valid-err', {tostring(date)}), 0)endif nParts == 1 then-- This can be either a month name or a year.self.month = self:parseMonthName(parts[1])if not self.month thenself.year = parseYear(parts[1])if not self.year thendateError()endendelseif nParts == 2 then-- This can be any of the following formats:-- DD Month-- Month DD-- Month YYYY-- YYYY-MM-- MM-DDself.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 thendateError()endendelseself.month = self:parseMonthName(parts[2])if self.month then-- This is DD Month.self.format = 'ymd'self.day = parseDayOrMonth(parts[1])if not self.day thendateError()endelse-- This is MM-DD.self.month = parseMonth(parts[1])if self.month thenself.day = parseDay(parts[2])else-- This is YYYY-MM.self.year = parseYear(parts[1])self.month = parseMonth(parts[2])if not (self.year and self.month) thendateError()endendendendelseif nParts == 3 then-- This can be any of the following formats:-- DD Month YYYY-- Month DD, YYYY-- YYYY-MM-DD-- DD-MM-YYYYself.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 thendateError()endelseself.day = parseDayOrMonth(parts[1])if self.day thenself.month = self:parseMonthName(parts[2])if self.month then-- This is DD Month YYYY.self.format = 'ymd'self.year = parseYear(parts[3])if not self.year thendateError()endelse-- This is DD-MM-YYYY.self.format = 'ymd'self.month = parseDayOrMonth(parts[2])self.year = parseYear(parts[3])if not self.month or not self.year thendateError()endendelse-- This is YYYY-MM-DDself.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 thendateError()endendendendendfunction Dts:makeSortKey()local year, month, daylocal nYearDigits = N_YEAR_DIGITSif self:hasDate() thenyear = self.year or os.date("*t").yearif year < 0 thenyear = -MAX_YEAR - 1 - yearnYearDigits = nYearDigits + 1 -- For the minus signendmonth = self.month or 1day = self.day or 1else-- Blank {{dts}} transclusions should sort last.year = MAX_YEARmonth = 99day = 99endreturn string.format('%0' .. nYearDigits .. 'd-%02d-%02d-%04d',year, month, day, self.addkey or 0)endfunction Dts:getMonthName()if not self.month thenreturn ''endif self.isAbbreviated thenreturn self.monthsAbbr[self.month]elsereturn self.months[self.month]endendfunction Dts:makeDisplay()if self.format == 'hide' thenreturn ''endlocal 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 ret = {}if hasYear thenif self.year < 0 thenret[#ret + 1] = '公元前'endlocal displayYear = math.abs(self.year)displayYear = displayYear > 9999 and lang:formatNum(displayYear) or tostring(displayYear)ret[#ret + 1] = displayYearret[#ret + 1] = '年'endif hasMonth thenret[#ret + 1] = self.monthret[#ret + 1] = '月'endif hasDay thenret[#ret + 1] = self.dayret[#ret + 1] = '日'endreturn table.concat(ret)endfunction Dts:makeDisplayAbbr()if self.format == 'hide' thenreturn ''endlocal 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 ret = {}if hasYear thenif self.year < 0 thenret[#ret + 1] = 'BC'endlocal displayYear = math.abs(self.year)displayYear = displayYear > 9999 and lang:formatNum(displayYear) or tostring(displayYear)ret[#ret + 1] = displayYearif hasMonth or hasDay thenret[#ret + 1] = '/'endendif hasMonth thenret[#ret + 1] = self.monthif hasDay thenret[#ret + 1] = '/'endendif hasDay thenret[#ret + 1] = self.dayendreturn table.concat(ret)endfunction Dts:makeDisplayAbbrOrNoAbbr()if self.isAbbreviated thenreturn self:makeDisplayAbbr()elsereturn self:makeDisplay()endendfunction Dts:renderTrackingCategories()if self.hasDeprecatedParameters thenreturn '[[Category:Template:Date_table_sorting錯誤|廢]]'elsereturn ''endendfunction Dts:__tostring()local root = mw.html.create()-- Sort keyif self.isdebug thenroot:tag('span'):css('border', 'dotted 1px'):wikitext(self:makeSortKey())elseroot:tag('span'):addClass('sortkey'):css('display', 'none'):css('speak', 'none'):wikitext(self:makeSortKey())end-- Displayif self:hasDate() thenif self.isWrapping thenroot:wikitext(self:makeDisplayAbbrOrNoAbbr())elseroot:tag('span'):css('white-space', 'nowrap'):wikitext(self:makeDisplayAbbrOrNoAbbr())endend-- Tracking categoriesroot:wikitext(self:renderTrackingCategories())return tostring(root)end---------------------------------------------------------------------------------- Exports--------------------------------------------------------------------------------local p = {}function p._exportClasses()return {Dts = Dts}endp.errmsg = Dts.GetErrMsgFromOtherfunction p._main(args)--由於技術問題,無法處理中文的年月日,因此將其丟進 Module:Date_Convert 轉成 ISODate 再傳入,就不會錯-- not tonumber(args[1]) 排掉年分,{{fact|可以解析的2000-01-01}}if args[1] and not tonumber(args[1]) then--iferror預防丟入 Module:Date_Convert 的格式不支援但 Module:Date_table_sorting 支援args[1] = mw.getCurrentFrame():callParserFunction('#iferror', require('Module:Date_Convert')._converttime(args[1]), args[1])end--endlocal success, ret = pcall(function ()local dts = Dts.new(args)return tostring(dts)end)if success thenreturn retelseret = Dts.errmsg('error', {ret})if mw.title.getCurrentTitle().namespace == 0 then-- Only categorise in the main namespaceret = ret .. '[[Category:Template:Date_table_sorting錯誤]]'endreturn retendendfunction p.main(frame)local args = require('Module:Arguments').getArgs(frame, {wrappers = 'Template:Date table sorting',})return p._main(args)endreturn p
🔥 Top keywords: Thâu-ia̍h模組:ArgumentsCarles PuigdemontAngkor WatPang-chān:Bo̍k-lio̍k209 hêng chiâm-téngIōng-chiá thó-lūn:Ndgf741Ingenuity ti̍t-seng-kiTek-pia̍t:尋討Tek-pia̍t:最近其改變Wiki Baike模組:Namespace detect/dataGamelanTwitterYosemite Kok-ka Kong-hn̂gTikTokBaike: Siā-lí mn̂g-chhùi-kháuÌn-nîBaike: Chhiū-á-khaSin-bûn sū-kiāⁿBaike: It-poaⁿ ê seng-bêngEnglandMediaWikiTexasBaike: Tāi-sài-koánTek-pia̍t:我其貢獻Hâng-lia̍tBaike: Hoan-gêng sin iōng-chiáChúi-keWikiPortal Sin-bûn sū-kiāⁿEdgeworth (Pennsylvania)Baike: Chiūⁿ-bāngRené DescartesSiōng-hái kuí-tō kau-thong 4-hō sòaⁿNorth CarolinaISO 8601Baike: Bián-chek seng-bêngBân-lâm-gúWiktionaryTek-pia̍t:我其討論DNAChýně1981 nîRobin WilliamsChū-iû lōe-iôngAlxa Chó-kîLūi-pia̍t:Kong-kek-hêng chhàng-kàmFontecchioIslam Kok (cho͘-chit)Thó-lūn:Thâu-ia̍hIslam kokAl-Nuri ê Tōa Chheng-chin-sīPang-chān:Lūi-pia̍t1771 nîRosalind Franklin1896 nîLūi-pia̍t:Kok-lūi chhàng-kàmÔng Hó͘-lêngMitch McConnellMichelle ObamaBí-kok Pe̍h-lângBaike: Tù-chok-koânBí-kokBāng-ia̍h liû-lám-khìTē-jī-chhù Sè-kài Tāi-chiànBîn-cho̍k-chú-gīISBNWikiSuleiman 1-sè (Pho-su)Lō͘-se-aWikinewsx3ooaPedivigliano1557 nîSoàn-thâuPek-kho-choân-su1272 nîJihadIrvington (New Jersey)Kordestan-e BozorgTrieste1401 nîVrbice (Břeclav)1739 nîWayback MachineLūi-pia̍t:Ìn-nîLūi-pia̍t:Kok-luī chhàng-kàmÍ-sek-lia̍tPe̍h-ōe-jī1623 nîWikidata1790 nîGreen Lake Kūn (Wisconsin)Elizabeth 2-sè1989 nîHeng-ta̍t Hoat-tiān-chhiángElmore (Ohio)Velletri