Module:ISOdate: Difference between revisions
From The Goon Show Depository
en>Mike Peel m (Protected "Module:ISOdate": High-risk Lua module ([Edit=Require template editor access] (indefinite) [Move=Require template editor access] (indefinite))) |
c>Jarekt (code clean-up to break it into smaller pieces and retire unused parts) |
||
Line 1: | Line 1: | ||
--[[ | --[[ | ||
__ __ _ _ ___ ____ ___ _ _ | |||
| \/ | ___ __| |_ _| | ___ _|_ _/ ___| / _ \ __| | __ _| |_ ___ | |||
| |\/| |/ _ \ / _` | | | | |/ _ (_)| |\___ \| | | |/ _` |/ _` | __/ _ \ | |||
| | | | (_) | (_| | |_| | | __/_ | | ___) | |_| | (_| | (_| | || __/ | |||
|_| |_|\___/ \__,_|\__,_|_|\___(_)___|____/ \___/ \__,_|\__,_|\__\___| | |||
This module is intended for processing of date strings. | This module is intended for processing of date strings. | ||
Line 9: | Line 14: | ||
* User:Parent5446 - original version of the function mimicking template:ISOdate | * User:Parent5446 - original version of the function mimicking template:ISOdate | ||
* User:Jarekt - original version of the functions mimicking template:Date and template:ISOyear | * User:Jarekt - original version of the functions mimicking template:Date and template:ISOyear | ||
]] | ]] | ||
-- ======================================= | -- ======================================= | ||
-- === Dependencies ====================== | -- === Dependencies ====================== | ||
-- ======================================= | -- ======================================= | ||
local | local Date = require('Module:DateI18n')._Date | ||
-- | -- ======================================= | ||
-- === Local Functions =================== | |||
-- ======================================= | |||
function | local function parse_ISOdate(datestr) | ||
-- Core function of this module, which splits "datestr" contining date in ISO format into Year, month, day, ... components | |||
-- Output is "datevec" array with numbers representing date components. We also return "tail" storing text following the date | |||
-- | |||
-- pattern: regexp - regular expresion to test; dlen - number of date elements; tail = which element is a "tail" if any | -- pattern: regexp - regular expresion to test; dlen - number of date elements; tail = which element is a "tail" if any | ||
Line 129: | Line 57: | ||
-- create datevec based on which variables are provided | -- create datevec based on which variables are provided | ||
local datevec, | local datevec = {} | ||
local tail = '' | |||
if datevec[1] | for i, pat in ipairs( patterns ) do | ||
local vec = {datestr:match( pat.regexp )} | |||
if vec and vec[1]~=nil then | |||
for j=1, pat.dlen do | |||
datevec[j] = vec[j] | |||
end | |||
if pat.tail>0 and vec[pat.tail]~=nil then | |||
tail = mw.ustring.gsub(' ' .. vec[pat.tail], ' +', ' ') | |||
end | |||
break | |||
end | |||
end | |||
if not datevec[1] or datevec[1]=='' then | |||
-- quickly return if datestr does not look like date (it could be a template) | -- quickly return if datestr does not look like date (it could be a template) | ||
return datestr, false | return nil, nil | ||
end | |||
return datevec, tail | |||
end | |||
-- ================================================== | |||
-- === External functions =========================== | |||
-- ================================================== | |||
local p = {} | |||
-- =========================================================================== | |||
-- === Version of the function to be called from other LUA codes | |||
-- =========================================================================== | |||
function p._ISOyear( datestr ) | |||
-- if empty string then return it | |||
datestr = mw.text.trim(datestr or '' ) | |||
if datestr == '' then | |||
return '' | |||
end | |||
-- if number then return it | |||
if tonumber( datestr ) then | |||
return mw.ustring.format( '%04i', datestr ) | |||
end | |||
-- otherwise use regular expression match | |||
datestr = mw.ustring.match( datestr, '^+?(-?%d%d?%d?%d?)-' ) | |||
if datestr and tonumber( datestr ) then | |||
return mw.ustring.format( '%04i', datestr ) | |||
else | |||
return '' | |||
end | |||
end | |||
function p._ISOdate(datestr, lang, case, class, trim_year) | |||
datestr = mw.text.trim(datestr or '' ) | |||
local datevec, tail = parse_ISOdate(datestr) | |||
if not datevec then | |||
return datestr, false -- quickly return if datestr does not look like date (it could be a template) | |||
end | end | ||
-- call p._Date function to format date string | -- call p._Date function to format date string | ||
local | local datestr2 = Date(datevec, lang, case, class, trim_year) | ||
if datestr2~='' then | |||
if | |||
return mw.text.trim( datestr2 .. tail), true | return mw.text.trim( datestr2 .. tail), true | ||
else -- in case of errors return the original string | else -- in case of errors return the original string | ||
Line 146: | Line 125: | ||
end | end | ||
-- =========================================================================== | |||
-- === Versions of the function to be called from template namespace | |||
-- =========================================================================== | |||
--[[ | |||
ISOdate | |||
This function is the core part of the ISOdate template. | |||
Usage: | |||
{{#invoke:ISOdate|ISOdate|target_string|lang=}} | |||
Parameters: | |||
1: The date string | |||
lang: The language to display it in | |||
form: Language format (genitive, etc.) for some languages | |||
class: CSS class for the <time> node | |||
Error Handling: | |||
local args = frame.args | If the string does not look like it contain the proper ISO date than the function will return the original string. | ||
That is the preferred treatment for the template:Information (and similar templates) which calling it. | |||
]] | |||
function p.ISOdate(frame) | |||
local args = {} | |||
for name, value in pairs( frame.args ) do | |||
if value ~= '' then -- nuke empty strings | |||
if type(name)=='string' then | |||
name = string.gsub( string.lower(name), ' ', '_') | |||
end | |||
args[name] = value | |||
end | |||
end | end | ||
datestr, succeded = p._ISOdate( | |||
local datestr, succeded = p._ISOdate( | |||
args[1] or '', | |||
args.lang, -- language | args.lang, -- language | ||
args.case | args.case, -- allows to specify grammatical case for the month for languages that use them | ||
args.class or 'dtstart', -- allows to set the html class of the time node where the date is included. | args.class or 'dtstart', -- allows to set the html class of the time node where the date is included. | ||
args.trim_year or '100-999' -- by default pad one and 2 digit years to be 4 digit long, while keeping 3 digit years as is | args.trim_year or '100-999' -- by default pad one and 2 digit years to be 4 digit long, while keeping 3 digit years as is | ||
) | ) | ||
return datestr | return datestr | ||
end | end | ||
--[[ | |||
ISOyear | |||
This function returns year part of date string. | |||
Usage: | |||
{{#invoke:ISOdate|ISOyear|target_string}} | |||
Parameters | |||
1: The date string | |||
Error Handling: | |||
If the string does not look like it contain the year than the function will not return anything. | |||
That is the preferred treatment for the template:Creator which is the main (only?) template calling it. | |||
]] | |||
function p.ISOyear( frame ) | |||
return p._ISOyear( frame.args[1] ) | |||
end | end | ||
return p | return p |
Revision as of 19:50, 8 May 2022
--[[
__ __ _ _ ___ ____ ___ _ _
| \/ | ___ __| |_ _| | ___ _|_ _/ ___| / _ \ __| | __ _| |_ ___
| |\/| |/ _ \ / _` | | | | |/ _ (_)| |\___ \| | | |/ _` |/ _` | __/ _ \
| | | | (_) | (_| | |_| | | __/_ | | ___) | |_| | (_| | (_| | || __/
|_| |_|\___/ \__,_|\__,_|_|\___(_)___|____/ \___/ \__,_|\__,_|\__\___|
This module is intended for processing of date strings.
Please do not modify this code without applying the changes first at Module:ISOdate/sandbox and testing
at Module:ISOdate/sandbox/testcases and Module talk:ISOdate/sandbox/testcases.
Authors and maintainers:
* User:Parent5446 - original version of the function mimicking template:ISOdate
* User:Jarekt - original version of the functions mimicking template:Date and template:ISOyear
]]
-- =======================================
-- === Dependencies ======================
-- =======================================
local Date = require('Module:DateI18n')._Date
-- =======================================
-- === Local Functions ===================
-- =======================================
local function parse_ISOdate(datestr)
-- Core function of this module, which splits "datestr" contining date in ISO format into Year, month, day, ... components
-- Output is "datevec" array with numbers representing date components. We also return "tail" storing text following the date
-- pattern: regexp - regular expresion to test; dlen - number of date elements; tail = which element is a "tail" if any
-- regexp hints:
-- 1) Strings starting with "^" and ending with "$" indicate whole string match
-- 2) optional tail part copied as-is and following the main parsed part of the date have to be separated from the date by a whitespace, so "(\s.+)?"
local patterns = {
-- strings starting with YYYY-MM-DD HH:MM:SS. Year 4 digits (if we know seconds than it was within the last 100 years), the rest 1-2
-- date and time can be separated by space or "T" and there could be a "Z" on the end indicating "Zulu" time zone
{dlen=6, tail=7, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?):(%d%d?)Z?(%s.*)"},
{dlen=6, tail=0, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?):(%d%d?)Z?$"},
-- strings starting with YYYY-MM-DD HH:MM. Year 4 digits, the rest 1-2
-- (if one knows hour and minute than it was probably after a year 1000)
{dlen=5, tail=6, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?)(%s.+)"},
{dlen=5, tail=0, regexp="^+?(%d%d%d%d)-(%d%d?)-(%d%d?)[ T](%d%d?):(%d%d?)$"},
-- strings starting with YYYY-MM-DD. Year 1-4 digits, the rest 1-2
{dlen=3, tail=4, regexp="^+?(%d%d?%d?%d?)-(%d%d?)-(%d%d?)(%s.+)"},
{dlen=3, tail=0, regexp="^+?(%d%d?%d?%d?)-(%d%d?)-(%d%d?)$"},
-- strings starting with YYYY-MM. Year 3-4 digits, month 2 digits
-- (want to avoit converting to dates strings like 10-5 = 5
{dlen=2, tail=3, regexp="^+?(%d%d%d%d?)-(%d%d)(%s.+)"},
-- if whole string is in YYYY-MM form: If Year 1-4 digits, month 1-2 digits
{dlen=2, tail=0, regexp="^+?(%d%d?%d?%d?)-(%d%d?)$"},
-- string starts with a number -> it has to be 3 or 4 digit long to be a year
{dlen=1, tail=2, regexp="^+?(%d%d%d%d?)(%s.+)"},
-- if whole string is a number (1-4 digit long) than it will be interpreted as a year
{dlen=1, tail=0, regexp="^+?(%d%d?%d?%d?)$"},
}
-- create datevec based on which variables are provided
local datevec = {}
local tail = ''
for i, pat in ipairs( patterns ) do
local vec = {datestr:match( pat.regexp )}
if vec and vec[1]~=nil then
for j=1, pat.dlen do
datevec[j] = vec[j]
end
if pat.tail>0 and vec[pat.tail]~=nil then
tail = mw.ustring.gsub(' ' .. vec[pat.tail], ' +', ' ')
end
break
end
end
if not datevec[1] or datevec[1]=='' then
-- quickly return if datestr does not look like date (it could be a template)
return nil, nil
end
return datevec, tail
end
-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}
-- ===========================================================================
-- === Version of the function to be called from other LUA codes
-- ===========================================================================
function p._ISOyear( datestr )
-- if empty string then return it
datestr = mw.text.trim(datestr or '' )
if datestr == '' then
return ''
end
-- if number then return it
if tonumber( datestr ) then
return mw.ustring.format( '%04i', datestr )
end
-- otherwise use regular expression match
datestr = mw.ustring.match( datestr, '^+?(-?%d%d?%d?%d?)-' )
if datestr and tonumber( datestr ) then
return mw.ustring.format( '%04i', datestr )
else
return ''
end
end
function p._ISOdate(datestr, lang, case, class, trim_year)
datestr = mw.text.trim(datestr or '' )
local datevec, tail = parse_ISOdate(datestr)
if not datevec then
return datestr, false -- quickly return if datestr does not look like date (it could be a template)
end
-- call p._Date function to format date string
local datestr2 = Date(datevec, lang, case, class, trim_year)
if datestr2~='' then
return mw.text.trim( datestr2 .. tail), true
else -- in case of errors return the original string
return datestr, false
end
end
-- ===========================================================================
-- === Versions of the function to be called from template namespace
-- ===========================================================================
--[[
ISOdate
This function is the core part of the ISOdate template.
Usage:
{{#invoke:ISOdate|ISOdate|target_string|lang=}}
Parameters:
1: The date string
lang: The language to display it in
form: Language format (genitive, etc.) for some languages
class: CSS class for the <time> node
Error Handling:
If the string does not look like it contain the proper ISO date than the function will return the original string.
That is the preferred treatment for the template:Information (and similar templates) which calling it.
]]
function p.ISOdate(frame)
local args = {}
for name, value in pairs( frame.args ) do
if value ~= '' then -- nuke empty strings
if type(name)=='string' then
name = string.gsub( string.lower(name), ' ', '_')
end
args[name] = value
end
end
local datestr, succeded = p._ISOdate(
args[1] or '',
args.lang, -- language
args.case, -- allows to specify grammatical case for the month for languages that use them
args.class or 'dtstart', -- allows to set the html class of the time node where the date is included.
args.trim_year or '100-999' -- by default pad one and 2 digit years to be 4 digit long, while keeping 3 digit years as is
)
return datestr
end
--[[
ISOyear
This function returns year part of date string.
Usage:
{{#invoke:ISOdate|ISOyear|target_string}}
Parameters
1: The date string
Error Handling:
If the string does not look like it contain the year than the function will not return anything.
That is the preferred treatment for the template:Creator which is the main (only?) template calling it.
]]
function p.ISOyear( frame )
return p._ISOyear( frame.args[1] )
end
return p