Module:Person date: Difference between revisions
Jump to navigation
Jump to search
(Account for the presence of disappeared_date per this thread) |
m (1 revision imported) |
||
(No difference)
| |||
Latest revision as of 19:51, 15 November 2025
Documentation for this module may be created at Module:Person date/doc
require("strict")
local p = {}
local TEMPLATES = {
birth_date = "Birth date",
birth_date_and_age = "Birth date and age",
birth_year = "Birth year",
birth_year_and_age = "Birth year and age",
death_date = "Death date",
death_date_text = "Death date text",
death_date_and_age = "Death date and age",
death_year = "Death year",
death_year_and_age = "Death year and age",
}
local invalid_date_category = ''
local tracking_category = ''
local Date = require('Module:Date')._Date
local getArgs = require('Module:Arguments').getArgs
if mw.title.getCurrentTitle():inNamespaces(0, 828, 829) then
-- Category only in namespaces: 0=article, 828=module & 829=module talk (last 2 needed for testcases)
tracking_category = '[[Category:Pages where birth or death is being automatically determined]]'
invalid_date_category = '[[Category:Pages with invalid birth or death dates]]'
end
local function check_for_invalid_date(str)
return mw.ustring.match(str, '^%?') or mw.ustring.match(str, '^%d%d%?') or mw.ustring.match(str, '^[Uu]nk')
end
local function expand_template(template, args)
return mw.getCurrentFrame():expandTemplate{title = template, args = args}
end
local function parse_date(str)
local date = Date(str)
if date then
return tostring(date.year), tostring(date.month), tostring(date.day)
end
-- TODO: Date has not been parsed. Need to work out what to do. For now, throw an error.
-- Example where this can occur: "birth_date = 22 December 1946" at [[Maurice Pasternak]].
-- There was a nonbreaking space after "22" whidh Date does not accept.
error('Module:Person_date parse_date invalid date: "' .. tostring(str) .. '"')
end
local 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
local 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
local 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
local 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
local function is_year_only(str)
return mw.ustring.match(str, '^%d%d%d%d$')
end
local 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
local function sanatize_date(str)
-- Sanatize leading & trailing whitespace (this caused an issue before it was implemented)
str = mw.ustring.gsub(str,'^%s*','')
str = mw.ustring.gsub(str,'%s*$','')
-- Sanatize ordinals
str = mw.ustring.gsub(str, '(%d+)st([,%s])', '%1%2')
str = mw.ustring.gsub(str, '(%d+)rd([,%s])', '%1%2')
str = mw.ustring.gsub(str, '(%d+)th([,%s])', '%1%2')
str = mw.ustring.gsub(str, '(%d+)nd([,%s])', '%1%2')
return str
end
local function parse_birth(args)
local birth_date = args['birth_date'] or args[1] or ''
local death_date = args['death_date'] or args[2] or ''
local disap_date = args['disappeared_date'] or ''
local original = birth_date
birth_date = sanatize_date(birth_date)
death_date = sanatize_date(death_date)
disap_date = sanatize_date(disap_date)
-- Check for bad inputs. This used to be covered by a switch statement in infoboxes
if check_for_invalid_date(birth_date) then
return original..invalid_date_category
end
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 == '' and disap_date == '' then
return expand_template(TEMPLATES.birth_date_and_age, {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 expand_template(TEMPLATES.birth_date, {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 == '' and disap_date == '' then
return expand_template(TEMPLATES.birth_year_and_age, {year, month}) .. extra
elseif is_year_only(death_date) or is_valid_date(death_date) or is_month_year_only(death_date) then
return expand_template(TEMPLATES.birth_year, {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 == '' and disap_date == '' then
return expand_template(TEMPLATES.birth_year_and_age, {date}) .. extra
elseif is_year_only(death_date) or is_valid_date(death_date) then
return expand_template(TEMPLATES.birth_year, {date}) .. extra
else
-- death_date is not a valid string (example: 'unknown')
return original
end
end
return original
end
local function parse_death(args)
local birth_date = args['birth_date'] or args[1] or ''
local death_date = args['death_date'] or args[2] or ''
local original = death_date
birth_date = sanatize_date(birth_date)
death_date = sanatize_date(death_date)
-- Check for bad inputs. This used to be covered by a switch statement in infoboxes
if check_for_invalid_date(death_date) then
return original..invalid_date_category
end
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 expand_template(TEMPLATES.death_date_text, {date}) .. extra
end
local year, month, day = parse_date(date)
return expand_template(TEMPLATES.death_date, {year, month, day, [format] = 'yes'}) .. extra
else
if is_year_only(birth_date) then
location = mw.ustring.find(birth_date, '%d%d%d%d')
local bd = mw.ustring.sub(birth_date, 1,location+3)
if is_month_year_only(death_date) then
return expand_template(TEMPLATES.death_date_and_age, {date, bd}) .. extra
end
return expand_template(TEMPLATES.death_date_and_age, {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')
local bd = mw.ustring.sub(birth_date, 1,location+3)
if (is_month_year_only(death_date)) then
return expand_template(TEMPLATES.death_date_and_age, {date, bd}) .. extra
end
return expand_template(TEMPLATES.death_date_and_age, {date, bd, [format] = 'yes'}) .. extra
end
end
end
if is_year_only(death_date) then
if birth_date == '' then
return expand_template(TEMPLATES.death_year, {mw.ustring.sub(death_date, 1, 5)}) .. mw.ustring.sub(death_date, 5) .. tracking_category
else
if is_year_only(birth_date) then
return expand_template(TEMPLATES.death_year_and_age, {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')
local bd = mw.ustring.sub(birth_date, 1,location+3)
return expand_template(TEMPLATES.death_date_and_age, {date, bd}) .. extra
end
end
end
end
return original
end
function p.birth(frame)
return parse_birth(getArgs(frame, {parentFirst = true}))
end
function p.death(frame)
return parse_death(getArgs(frame, {parentFirst = true}))
end
return p