--[[
Calculates years between two dates, for example birth date and death date.
Input dates can be in any of these formats:
"1999-12-31"
"1999-12"
"1999"
"31 december 1999"
"31 dec 1999"
"december 1999"
"dec 1999"
also dates with links are accepted, ie "[31 december] [1999]"
case doesnt matter, "31 DECEMBER 1999"
"f.Kr." (BC) and "e.Kr." (AD) allowed, ie "300 f.Kr."
Usage:
====== age ======================================
Years between now and a date
{{#DateHelper|age|12 december 1975}}
Years between two dates
{{#DateHelper|age|12 december 1975|1 januari 2003}}
Result will be in these forms:
"87 år"
"87 eller 88 år" (range if years without month or day give)
"" (if error)
====== date conversion ==========================
Date to iso-date
{{#DateHelper|to_iso|31 december 1975}}
returns: "1975-12-31"
Date to short date
{{#DateHelper|to_short|1975-12-31}}
returns: "31 dec 1975"
Date to long date
{{#DateHelper|to_long|1975-12-31}}
returns: "31 december 1975"
====== date conversion with links ===============
{{#DateHelper|to_short|1975-12-31|link}}
returns: "[31 december|31 dec] [1975]"
{{#DateHelper|to_long|1975-12-31|link}}
returns: "[31 december] [1975]"
{{#DateHelper|to_short|1975-12-31|link}}
returns: "[31 december|31 dec] [Konstår 1975|1975]"
{{#DateHelper|to_long|1975-12-31|link:Konstår}}
returns: "[31 december] [Konstår 1975|1975]"
]]
local main = {};
local months_long={'januari','februari','mars','april','maj','juni','juli','augusti','september','oktober','november','december'}
local months_short={'jan','feb','mar','apr','maj','jun','jul','aug','sep','okt','nov','dec'}
local useEkrFkr -- flag that "e.Kr." or "f.Kr." (ED/BC) was used on input string and so should also be used in output
local nbsp=' '
-- split string s into an array
function split(s, delimiter)
result = {};
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
table.insert(result, match);
end
return result;
end
-- remove links from text
local function removeLinks(text)
text=string.gsub(text,"%[%[[^%[%]]-|([^%[%]|]-)%]%]","%1") -- link, text separated by "|". Handles case of File: when no alt= is specified, -assuming- last field is the legend
text=string.gsub(text,"%[%[([^%[%]|]-)%]%]","%1") -- link with no funny |s at all
return text
end
-- remove trailing and leading whitespace from string.
-- http://en.wikipedia.org/wiki/Trim_(8programming)
local function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
-- convert month from string to number
local function convertmonth( month )
month = string.lower(month)
for i, m in ipairs(months_long) do
if m==month then return i end
end
for i, m in ipairs(months_short) do
if m==month then return i end
end
return -1
end
-- get max number of days in a month
local function daysInMonth(month)
if month==2 then
return 29
elseif month==4 or month==6 or month==9 or month==11 then
return 30
else
return 31
end
end
-- takes 3 strings and returns a date object
-- input:year="1999", month="12", day="31"
-- output: {year=1999,month=12,day=31} or nil if date not valid
local function createDateObject(year,month,day,bc)
local year=tonumber(year)
if bc then
year=-year
end
local month=tonumber(month)
local day=tonumber(day)
if year==nil or month ==nil or day == nil then return nil end
if month<0 or month >12 then return nil end
if day<0 or day>daysInMonth(month) then return nil end
return {year=year,month=month,day=day}
end
-- convert date string to date format
-- input: a date string, example "1930 e.Kr." "1956-12-20" "12 dec 1940" "januari 2001"
-- output: {year=1999,month=12,day=31} or nil if not valid
local function convertdate( date )
local bc=false --negativ years
date=removeLinks(date)
date=trim(date)
date=date:lower()
local pos
pos=date:find('e%p?kr')
if (pos~=nil) then
useEkrFkr=true
date=date:sub(1,pos-1)
else
pos=date:find('f%p?kr')
if (pos~=nil) then
useEkrFkr=true
bc=true
date=date:sub(1,pos-1)
end
end
-- Check if date in numeric format (1999 or 1999-12 or 1999-12-31)
if not string.match ( date ,"%a" ) then
date=date:gsub(' ','') -- remove all spaces
local datesplit=split(date, "-")
local count=table.getn(datesplit)
if count==1 then
return createDateObject(datesplit[1],0,0,bc)
end
if count==2 then
return createDateObject(datesplit[1],datesplit[2],0,bc)
end
if count==3 then
return createDateObject(datesplit[1],datesplit[2],datesplit[3],bc)
end
return nil
end
-- Date with written month, "31 dec(ember) 1999" or "dec(ember) 1999"
date=string.gsub(date, "%s+", " ")
local datesplit=split(date, " ")
local count=table.getn(datesplit)
if count==2 then
return createDateObject(datesplit[2],convertmonth(datesplit[1]),0,bc)
end
if count==3 then
return createDateObject(datesplit[3],convertmonth(datesplit[2]),datesplit[1],bc)
end
return nil
end
-- takes two date objects and returns number of years between them
-- both dates must have year, month and day
local function yearsBetweenDates(date1,date2)
if date1.year>date2.year or
(date1.year==date2.year and date1.month>date2.month ) or
(date1.year==date2.year and date1.month==date2.month and date1.day>date2.day ) then
local tmp=date1
date1=date2
date2=tmp
end
local years=date2.year-date1.year
if date1.month>date2.month or ((date1.month==date2.month) and date1.day>date2.day) then
years=years-1
end
return years
end
-- takes two date objects and returns number of years between them
-- both dates must have year. Month and day are optional.
local function yearsBetweenUnfixedDates(date1,date2)
local date1_hi,date1_low
local date2_hi,date2_low
if date1.month>0 and date1.day>0 then
date1_low=date1
date1_hi=date1
elseif date1.month>0 then
date1_low={year=date1.year,month=date1.month,day=1}
date1_hi={year=date1.year,month=date1.month,day=daysInMonth(date1.month)}
else
date1_low={year=date1.year,month=1,day=1}
date1_hi={year=date1.year,month=12,day=31}
end
if date2.month>0 and date2.day>0 then
date2_low=date2
date2_hi=date2
elseif date2.month>0 then
date2_low={year=date2.year,month=date2.month,day=1}
date2_hi={year=date2.year,month=date2.month,day=daysInMonth(date2.month)}
else
date2_low={year=date2.year,month=1,day=1}
date2_hi={year=date2.year,month=12,day=31}
end
local years1=yearsBetweenDates(date1_low,date2_hi)
local years2=yearsBetweenDates(date1_hi,date2_low)
if years1==years2 then
return years1
elseif years1>years2 then
return years2..' eller '..years1
else
return years1..' eller '..years2
end
end
local function checkLinkArg(larg)
if (larg==nil) then
linkArg=''
elseif (larg:lower()=='link') then
linkArg='link'
else
local cpos=larg:find(':')
if cpos~=nil then
linkArg=larg:sub(cpos+1)
end
end
end
local function createLinkText(link,text)
if text==nil or text=='' then
return ''
elseif link==nil or link=='' then
return text
elseif link==text then
return '[['..text..']]'
else
return '[['..link..'|'..text..']]'
end
end
---------------------------------------------------------------------------
function main.format(date,link,longFormat)
local makeLinks=false
local linkPrefix=''
-- Process link argument
-- can be: nil, "", "link", "link:" or "link:Prefix"
if (link==nil or link=="") then
makeLinks=false
elseif (link:lower()=='link' or link:lower()=='link:') then
makeLinks=true
linkPrefix=''
else
local cpos=link:find(':')
if cpos~=nil then
makeLinks=true
linkPrefix=link:sub(cpos+1)..' '
end
end
-- Process date arguement, if any error just return it
local dateObj=convertdate(date)
if dateObj==nil then
return date
end
-- Build the date string
-- date and month
local result=''
if dateObj.month>0 then
if (longFormat) then
result=months_long[dateObj.month]
else
result=months_short[dateObj.month]
end
if dateObj.day>0 then
result=dateObj.day..' '..result
if makeLinks then
result=createLinkText(dateObj.day..' '..months_long[dateObj.month],result)
end
end
result=result..' '
end
-- year
local yearString,yearLink
if dateObj.year<0 then
yearString=(-dateObj.year)..' f.Kr.'
yearLink=linkPrefix..yearString
elseif useEkrFkr and dateObj.year>0 then
yearString=dateObj.year..' e.Kr.'
yearLink=linkPrefix..dateObj.year
else
yearString=dateObj.year
yearLink=linkPrefix..yearString
end
if (not makeLinks) then
result=result..yearString
else
result=result..createLinkText(yearLink,yearString)
end
return result
end
function main.yearsBetween(date1,date2)
if (date1==nil or date1=='') then
return ''
end
if (date2==nil or date2=='') then
date2=os.date("%Y-%m-%d")
end
local dateObj1=convertdate(date1)
local dateObj2=convertdate(date2)
if dateObj1==nil or dateObj2==nil then
return ""
end
return yearsBetweenUnfixedDates(dateObj1,dateObj2) ..nbsp..'år'
end
function main.to_iso(input)
local input_date=input.args[1]
local date1=convertdate(input_date)
if date1==nil then
return input_date
end
local result=date1.year..'-'
if (date1.month)<10 then result=result..'0' end
result=result.. date1.month..'-'
if (date1.day)<10 then result=result..'0' end
result=result.. date1.day
return result
end
function main.to_long(input)
return main.format(input.args[1],input.args[2],true)
end
function main.to_short(input)
return main.format(input.args[1],input.args[2],false)
end
function main.age(input)
return main.yearsBetween(input.args[1],input.args[2])
end
return main