Module:Duration

From Wikidata
Jump to navigation Jump to search
Lua
CodeDiscussionLinksLink count SubpagesDocumentationTestsResultsSandboxLive code All modules

The module is meant for language-dependant time calculations.

This module transform arguments in the form ssss (any number of digits) in anglosaxon format (with a point before the thousand digits orwithout separators), to a "text expresion": millennia, centuries, years, days, hours, minutes, seconds, tenths, hundredths and thousandths.

Optional parameter format=hms show a reduced version of time units.

Examples[edit]

  • {{#invoke:Duration | sec2expr |7210}} returns: 2 hores and 10 segons
  • {{#invoke:Duration | sec2expr |6510.8}} returns: 1 hora, 48 minuts, 30 segons and 8 dècimes
  • {{#invoke:Duration | sec2expr |3580}} -> 59 minuts and 40 segons
  • {{#invoke:Duration | sec2expr |120.32 }} -> 2 minuts, 3 dècimes and 2 centèsimes
  • {{#invoke:Duration | sec2expr |50 }} -> 50 segons
  • {{#invoke:Duration | sec2expr |14.5 }} -> 14 segons and 5 dècimes

Amb format=hms

  • {{#invoke:Duration | sec2expr |6510.8 |format=hms}} returns: 1h 48′ 30.8″
  • {{#invoke:Duration | sec2expr |3580 |format=hms}} -> 59′ 40″
  • {{#invoke:Duration | sec2expr |14.5 |format=hms }} -> 14.5″
NOTE
to manage european notation figures (decimal comma and points), {{EUsec2expr}} must be used previously to invoke this module. Ex.:

Code

-- this module is meant for language-dependant time calculations.
local p = {}

--[[
function sumHMS accepts unnamed (aka "order based")
arguments in the form ssss (any number of digits) or "mm:ss" or "hh:mm:ss:,
converts them all to seconds, sums them up, and returns the output string 
describing the total duration, using mw.getContentLanguage():formatDuration()
an optional paramter, "units" tells the formatting function which units to use:
e.g. {{invoke:Duration | sumHMS | 7211 | units = minutes, seconds}} will return "120 minutes and 11 seconds".
{{invoke:Duration|sumHMS| 1:0:11 | 1:00:00 | units= seconds}} will return "7211 seconds"
]]

function p.sumHMS(frame)
	local args = frame.args
    local total = 0
    
    function oneMore( st )
        if type( st ) ~= 'string' then return end
        local t, ar = 0, { st:match( "^%s*(%d*%.?%d*):?(%d*):?(%d*)%s*$" ) }
        for _, v in ipairs( ar ) do
            local n = tonumber( v )
            if n then t = t * 60 + n end
        end
        total = total + t
    end

    for _, v in ipairs( args ) do oneMore( v ) end
    local units
    if args.units then 
        units = mw.text.split("%W+")
    end
    
    local lang_obj
    if args.lang and args.lang ~= '' then
    	lang_obj = mw.language.new(args.lang)
    else
    	lang_obj = mw.language.getContentLanguage()
    end
    return lang_obj:formatDuration( total, units )
end

function p.sec2expr(frame)
	-- i18n
	local local_lang = {["millenia"] = "mil·lenis", ["centuries"] = "segles", ["years"] = "anys", ["days"] = "dies",
		["hours"] = "hores", ["minutes"] = "minuts", ["seconds"] = "segons"}
	local decimals = {"dècimes", "centèsimes", "mil·lèsimes"}
	local sorted = {"mil·lenis", "segles", "anys", "dies", "hores", "minuts", "segons",
		"dècimes", "centèsimes", "mil·lèsimes"}
	local singular = {["mil·lenis"] = "mil·leni", ["segles"] = "segle", ["anys"] = "any", ["dies"] = "dia",
		["hores"] = "hora", ["minuts"] = "minut", ["segons"] = "segon",
		["dècimes"] = "dècima", ["centèsimes"] = "centèsima", ["mil·lèsimes"] = "mil·lèsima"}
	local units_hms = {["hores"] = "h", ["minuts"] = "′", ["segons"] = "″"}
	
	local args = frame.args
	local sec = tonumber(args[1])
	local formathms = string.lower(args.format or "") == "hms"
	
	local lang = mw.language.getContentLanguage()
	-- convert to table with units, truncates to seconds
	-- oddly it do not use ContentLanguage, units are in English
	local sec2table = lang:getDurationIntervals(sec, formathms and {"hours", "minutes", "seconds"} or nil)
	
	if formathms then
		sec2table["seconds"] = (sec2table["seconds"] or 0) + tonumber("." .. (tostring(sec):match("%.(%d+)") or "0"))
	end
	
	-- translate units
	local sec2local = {}
	for k, v in pairs(sec2table) do
		sec2local[local_lang[k]] = v
	end
	
	-- add decimals
	if not formathms then
		for i, v in ipairs(decimals) do
			local dec = math.floor(sec * 10^i % 10)
			if dec > 0 then
				sec2local[v] = dec
			end
		end
	end
	
	-- sort in a list
	local sec2list = {}
	for i, v in ipairs(sorted) do
		if sec2local[v] then
			if formathms then
				sec2list[1] = (sec2list[1] or "") .. lang:formatNum(sec2local[v]) .. units_hms[v] .. " "
			else
				sec2list[#sec2list + 1] = sec2local[v] .. " " .. (sec2local[v] == 1 and singular[v] or v)
			end
		end
	end
	
	return mw.text.listToText(sec2list)
end

return p