Module:Person date
Appearance
| This module is rated as ready for general use. It has reached a mature state, is considered relatively stable and bug-free, and may be used wherever appropriate. It can be mentioned on help pages and other Wikipedia resources as an option for new users. To minimise server load and avoid disruptive output, improvements should be developed through sandbox testing rather than repeated trial-and-error editing. |
| This module is currently protected from editing. See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected. |
| This Lua module is used on approximately 1,730,000 pages, or roughly 3% of all pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
This module is intended to aid in calculating/formatting birth dates and death dates in {{Infobox person}} and other People and person infobox templates.
This module generates errors when it encounters invalid input. Error descriptions and how to fix them are listed at Category:Pages using age template with invalid date.
Usage
{{#invoke:person date|birth}}{{#invoke:person date|death}}
In infoboxes
{{Infobox
...
| label# = Born
| data# = {{#invoke:person date|birth}}
| label# = Died
| data# = {{#invoke:person date|death}}
...
}}
Or
{{Infobox
...
| label# = Born
| data# = {{br separated entries
|1={{#if:{{{birth_name|}}}|<div style="display:inline" class="nickname">{{{birth_name|}}}</div>}}
|2={{#invoke:person date|birth}}
|3={{#if:{{{birth_place|}}}|<div class="birthplace">{{{birth_place|}}}</div>}}
}}
| label# = Died
| data# = {{br separated entries
|1={{#invoke:person date|death}}
|2={{#if:{{{death_place|}}}|<div class="deathplace">{{{death_place|}}}</div>}}
}}
...
}}
Areas for improvement
- Currently the module does not handle anything that is not a simple date. So anything with a reference tag is not evaluated by the code.
- If
|birth_date=(for example) then{{bda|1993|11|7}}|death_date=will not be parsed. It will just be returned as the original string. Thus no age is calculated.
Tracking categories
local p = {}
-- local MAX_AGE = 130
-- local error_text = 'Error: Invalid birth_date in [[Module:Person date]], violates MAX_AGE of '.. MAX_AGE
-- local category_text = '[[Category:Articles using module person date older than 130]]'
local tracking_category = ' '
local Date = require('Module:Date')._Date
if mw.title.getCurrentTitle():inNamespaces(0) then
-- Category only in namespaces: 0=article.
tracking_category = '[[Category:Pages where birth or death is being automatically determined]]'
end
function parse_date(str)
local day = Date(str):text('%-d')
local month = Date(str):text('%-m')
local year = Date(str):text('%Y')
return year, month, day
end
function date_format(str)
if mw.ustring.match (str, '^%d+%s*%a+%s*%d%d%d%d$') then
return 'df'
elseif mw.ustring.match(str, '^%a+%s+%d+,%s*%d%d%d%d$') then
return 'mf'
else
return 'ERROR'
end
end
function is_valid_month (str)
str = string.upper(mw.ustring.sub(str,1,1))..string.lower(mw.ustring.sub(str,2))
local months = {'Jan','Jan.','January','Feb','Feb.','February','Mar','March','Apr','Apr.','April','May','Jun','Jun.','June','Jul','Jul.','July','Aug','Aug.','August','Sep','Sept','Sep.','Sept.','September','Oct','Oct.','October','Nov','Nov','November','Dec','Dec.','December'}
for index, value in ipairs(months) do
if value == str then
return true
end
end
return false
end
function is_month_year_only(str)
local month = mw.ustring.match(str, '^(%a+)%s+%d%d%d%d$')
if month == nil then
return false
else
return is_valid_month(month)
end
end
function is_valid_date(str)
local month = mw.ustring.match (str, '^%d+%s*(%a+)%s*%d%d%d%d$') or mw.ustring.match(str, '^(%a+)%s+%d+,%s*%d%d%d%d$')
if month == nil then
return false
else
return is_valid_month(month)
end
end
function is_year_only(str)
return mw.ustring.match(str, '^%d%d%d%d$')
end
function already_has_template(str)
str = mw.ustring.gsub(str, '&[Nn][Bb][Ss][Pp];', ' ')
return mw.ustring.match(str, '<span') or mw.ustring.match(str, '<time') or mw.ustring.match(str,'%(aged%s*%d+') or mw.ustring.match(str,'%(age%s*%d+')
end
function parse_birth(frame, args)
local birth_date = args[1] or ''
local death_date = args[2] or ''
local original = birth_date
-- Sanatize leading & trailing whitespace (this caused an issue before it was implemented)
birth_date = mw.ustring.gsub(birth_date,'^%s*','')
birth_date = mw.ustring.gsub(birth_date,'%s*$','')
death_date = mw.ustring.gsub(death_date,'^%s*','')
death_date = mw.ustring.gsub(death_date,'%s*$','')
if already_has_template(birth_date) then
return original
end
if is_valid_date(birth_date) then
local location = mw.ustring.find(birth_date, '%d%d%d%d')
local extra = mw.ustring.sub(birth_date, location+4) .. tracking_category
local date = mw.ustring.sub(birth_date, 1,location+3)
local year, month, day = parse_date(date)
local format = date_format(date)
if death_date == '' then
return frame:expandTemplate{ title = 'Birth date and age', args = {year, month, day, [format] = 'yes'}} .. extra
elseif is_year_only(death_date) or is_valid_date(death_date) or is_month_year_only(death_date) then
return frame:expandTemplate{ title = 'Birth date', args = {year, month, day, [format] = 'yes'}} .. extra
else
-- death_date is not a valid string (example: 'unknown')
return original
end
end
if is_month_year_only(birth_date) then
local year = Date('1 '..birth_date):text('%Y')
local month = Date('1 '..birth_date):text('%-m')
local location = mw.ustring.find(birth_date, '%d%d%d%d')
local date = mw.ustring.sub(birth_date, 1,location+3)
local extra = mw.ustring.sub(birth_date, location+4) .. tracking_category
if death_date == '' then
return frame:expandTemplate{ title = 'Birth year and age', args = {year, month}} .. extra
elseif is_year_only(death_date) or is_valid_date(death_date) or is_month_year_only(death_date) then
return frame:expandTemplate{ title = 'Birth year', args = {date}} .. extra
else
-- death_date is not a valid string (example: 'unknown')
return original
end
end
if is_year_only(birth_date) then
local date = mw.ustring.sub(birth_date, 1, 5)
local extra = mw.ustring.sub(birth_date, 5) .. tracking_category
if death_date == '' then
return frame:expandTemplate{ title = 'Birth year and age', args = {date}} .. extra
elseif is_year_only(death_date) or is_valid_date(death_date) then
return frame:expandTemplate{ title = 'Birth year', args = {date}} .. extra
else
-- death_date is not a valid string (example: 'unknown')
return original
end
end
return original
end
function parse_death(frame, args)
local birth_date = args[1] or ''
local death_date = args[2] or ''
local original = death_date
-- Sanatize leading & trailing whitespace (this caused an issue before it was implemented)
birth_date = mw.ustring.gsub(birth_date,'^%s*','')
birth_date = mw.ustring.gsub(birth_date,'%s*$','')
death_date = mw.ustring.gsub(death_date,'^%s*','')
death_date = mw.ustring.gsub(death_date,'%s*$','')
if already_has_template(death_date) then
return original
end
if is_valid_date(death_date) or is_month_year_only(death_date) then
local location = mw.ustring.find(death_date, '%d%d%d%d')
local date = mw.ustring.sub(death_date, 1,location+3)
local extra = mw.ustring.sub(death_date, location+4) .. tracking_category
local format = date_format(date)
if birth_date == '' then
if is_month_year_only(death_date) then
return frame:expandTemplate{ title = 'Death date text', args = {date}} .. extra
end
local year, month, day = parse_date(date)
return frame:expandTemplate{ title = 'Death date', args = {year, month, day, [format] = 'yes'}} .. extra
else
if is_year_only(birth_date) then
location = mw.ustring.find(birth_date, '%d%d%d%d')
bd = mw.ustring.sub(birth_date, 1,location+3)
return frame:expandTemplate{ title = 'Death date and age', args = {date, bd, [format] = 'yes'}} .. extra
elseif is_valid_date(birth_date) or is_month_year_only(birth_date) then
location = mw.ustring.find(birth_date, '%d%d%d%d')
bd = mw.ustring.sub(birth_date, 1,location+3)
return frame:expandTemplate{ title = 'Death date and age', args = {date, bd, [format] = 'yes'}} .. extra
end
end
end
if is_year_only(death_date) then
if birth_date == '' then
return frame:expandTemplate{ title = 'Death year', args = {mw.ustring.sub(death_date, 1, 5)}} .. mw.ustring.sub(death_date, 5) .. tracking_category
else
if is_year_only(birth_date) then
return frame:expandTemplate{ title = 'Death year and age', args = {mw.ustring.sub(death_date, 1, 5), mw.ustring.sub(birth_date, 1, 5)}} .. mw.ustring.sub(death_date, 5) .. tracking_category
else
if is_valid_date(birth_date) then
local location = mw.ustring.find(death_date, '%d%d%d%d')
local date = mw.ustring.sub(death_date, 1,location+3)
local extra = mw.ustring.sub(death_date, location+4) .. tracking_category
location = mw.ustring.find(birth_date, '%d%d%d%d')
bd = mw.ustring.sub(birth_date, 1,location+3)
return frame:expandTemplate{ title = 'Death date and age', args = {date, bd}} .. extra
end
end
end
end
return original
end
-- function check_for_max_date(frame, text)
-- original_text = text
-- -- Sanatize text
-- text = mw.ustring.gsub(text, '&[Nn][Bb][Ss][Pp];', ' ')
-- text = mw.ustring.gsub(text, '<span class="currentage"></span>', '')
-- text = mw.ustring.gsub(text, '%(aged%s', '(age ')
-- -- Locate numbers in '(age #'
-- local regex = '%(age%s%d+'
-- local start, stop = mw.ustring.find(text, regex)
-- if start == nil or stop == nil then
-- return original_text
-- end
-- local age = mw.ustring.sub(text, start+mw.ustring.len(regex)-6, stop)
-- if tonumber(age) > MAX_AGE then
-- local error_msg = frame:expandTemplate{ title = 'error', args = {error_text}}
-- local category = frame:expandTemplate{ title = 'main other', args = {category_text}}
-- return original_text..error_msg..category
-- end
-- return original_text
-- end
function p.birth(frame)
return parse_birth(frame, frame.args[1] and frame.args or frame:getParent().args)
end
function p.death(frame)
return parse_death(frame, frame.args[1] and frame.args or frame:getParent().args)
end
return p