Module:Sandbox/Harry noob/Dates explained

--Harry noob Google Code-in 2019, Lua Task 9

--date formatM= word monthm= number month

d/m/yy/m/dm/d/yd M yM d yy MM yy

--

----

local p = local log = mw.log

function p.canonicalDate(frame) local fmt = frame.args.format local text = frame.args.text local date, defaultFmt = p.parseDate(text) if not date then return "Invalid entry" end local formattedDate = p.formatDate(date, fmt, defaultFmt) local result = addPreSuffix(text, formattedDate) return resultend

function p.parseDate(text) local d, m, y, a, b, c, mName local mayMatch log("try to match y/m/d or d/m/y or m/d/y") a, b, c = string.match(text, "(%d+)[/%- ](%d+)[/%- ](%d+)") -- y/m/d or d/m/y or m/d/y log(a, b, c) mayMatch = a and b and c local possibleArrangement = mw.logObject(possibleArrangement, "possibleArrangement: ") for _, arrange in ipairs(possibleArrangement) do y, m, d = unpack(arrange) -- this is not python :(need to add unpack, destructing assignment doesnt works with table if isValidNumDate(y, m, d) then log("isValidNumDate passed 1") return mapToNum, "iso" end end if mayMatch then return nil end local monthShortNameToNum = local monthLongNameToNum = -- match long name first, and then short name local monthFound = false local start, stop for monthName, monthNum in pairs(monthLongNameToNum) do start, stop = text:lower:find(monthName) log("month for loop 1:", monthName, monthNum, start, stop) if start and stop then monthFound = true mName = text:sub(start, stop) -- ~= monthName,

orginal month name log("mName:", mName) m = monthNum break end end if not monthFound then for monthName, monthNum in pairs(monthShortNameToNum) do if monthName

"sept" then start, stop = text:lower:find("sept?") else start, stop = text:lower:find(monthName) end if start and stop then monthFound = true mName = text:sub(start, stop) -- ~= monthName,

orginal month name log("mName:", mName) m = monthNum break end end end if monthFound then log("try to match d M y or y M d") d, y = text:match("(%d+)%D-" .. mName .. "%D-(%d+)") -- d M y if isValidNumDate(y, m, d) then log("isValidNumDate passed 2") return mapToNum, "dmy" end if d and y then return nil end log("try to match M d y") d, y = text:match(mName .. "%D-(%d+)%D-(%d+)") -- M d y if isValidNumDate(y, m, d) then log("isValidNumDate passed 4") return mapToNum, "mdy" end if d and y then return nil end log("try to match M y") y = text:match(mName .. "%D-(%d+)") -- M y log("y =", y) if y then return mapToNum, "my" end log("try to match y M") y = text:match("(%d+)%D-" .. mName) -- y M log("y =", y) if y then return mapToNum, "ym" end end log("try to match y") y = text:match("(%d+)%D-$") -- y if y then return, "year" end log("no match") return nilend

-- y, m, d are string numberfunction isValidNumDate(y, m, d) log("isValidNumDate receive:", y, m, d) y, m, d = tonumber(y), tonumber(m), tonumber(d) local NOfDays = local result = y and m and d and 1 <= m and m <= 12 and (isLeap(y) and m

2 and 1 <= d and -- if is leap year and February (d <= 29) or -- then test if it <= 29 (d <= NOfDays[m])) -- else follow general case (use assert and pcall instead of returning 2 result can type less code) log("isValidNumDate result:" .. tostring(result)) return resultend

function isLeap(y) return y%4

0 and (y%100 ~= 0 or y%400

0)end

function mapToNum(arr) mw.logObject(arr, "mapToNum receive arr:") for i, v in pairs(arr) do arr[i] = tonumber(v) end mw.logObject(arr, "mapToNum result arr:") return arrend

function p.formatDate(date, fmt, defaultFmt) local monthNames = local y, m, d = unpack(date) if (fmt or defaultFmt)

"iso" then return ("%d-%02d-%02d"):format(y, m, d) elseif (fmt or defaultFmt)

"dmy" then return ("%d %s %d"):format(d, monthNames[m], y) elseif (fmt or defaultFmt)

"mdy" then return ("%s %d, %d"):format(monthNames[m], d, y) elseif (fmt or defaultFmt)

"my" then return ("%s %d"):format(monthNames[m], y) elseif (fmt or defaultFmt)

"ym" then return ("%d %s"):format(y, monthNames[m]) else return tostring(y) endend

function addPreSuffix(text, dateStr) local aboutList = local suffixList = for i, word in ipairs(aboutList) do if text:lower:find(word) then dateStr = "circa " .. dateStr break end end for i, word in ipairs(suffixList) do if text:find(" " .. word) then dateStr = dateStr .. " " .. word break end end return dateStrend

return p