Module:Sandbox/AlphaZeta/test3

--[[ 
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