Module:Age: Difference between revisions

From Offetstine Wiki
m (Parametrize in terms of Scribunto template parameters)
((hack) fix year/month ages, kinda)
 
Line 30: Line 30:
end
end


local function age(iso, iso_now)
local function age(iso_then, iso_now)
local parsed = parse_iso(iso)
local then_parts = parse_iso(iso_then)
if not parsed then
if not then_parts then
return nil
return nil
end
end
local now
local now
local now_parts
if iso_now then
if iso_now then
local parts = parse_iso(iso_now)
now_parts = parse_iso(iso_now)
if not parts then
if not now_parts then
return nil
return nil
end
end
now = os.time(parts)
now = os.time(now_parts)
else
else
now = os.time()
now = os.time()
end
end
local then_ = os.time(parsed)
local then_ = os.time(then_parts)
local diff = now - then_
local diff = now - then_


Line 56: Line 57:
local days = diff % 30
local days = diff % 30
diff = math.floor(diff / 30)
diff = math.floor(diff / 30)
local months = diff % 12
--local months = diff % 12
diff = math.floor(diff / 12)
--diff = math.floor(diff / 12)
local years = diff
--local years = diff
 
local months = now_parts.month - then_parts.month
local years = now_parts.year - then_parts.year
if months < 0 then
months = months + 12
years = years - 1
end


return {
return {
Line 151: Line 159:
format_date = date_mw,
format_date = date_mw,
retro = retro_mw,
retro = retro_mw,
age = age,
}
}

Latest revision as of 07:57, 20 September 2023

Documentation for this module may be created at Module:Age/doc

-- Scribunto Lua plugin to convert an ISO date-time (1970-01-01T00:00:00Z) or
-- date (1970-01-01) to an English human-readable date (1 January 1970) and
-- age (50 years old).

local function parse_iso(iso)
	local year, month, day, hour, minute, second =
		iso:match('^(%d%d%d%d)-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)Z$')
	if not year then
		year, month, day = iso:match('^(%d%d%d%d)-(%d%d)-(%d%d)$')
		if not year then
			return nil
		end
		hour, minute, second = 0, 0, 0
	end
	return {
		year = tonumber(year),
		month = tonumber(month),
		day = tonumber(day),
		hour = tonumber(hour),
		minute = tonumber(minute),
		second = tonumber(second),
	}
end

-- Automatically return a timestamp some number of years in the past.
local function retro(offset)
	local now = os.time()
	local then_ = now - (offset * 365 * 24 * 60 * 60)
	return os.date('!%Y-%m-%dT%H:%M:%SZ', then_)
end

local function age(iso_then, iso_now)
	local then_parts = parse_iso(iso_then)
	if not then_parts then
		return nil
	end
	local now
	local now_parts
	if iso_now then
		now_parts = parse_iso(iso_now)
		if not now_parts then
			return nil
		end
		now = os.time(now_parts)
	else
		now = os.time()
	end
	local then_ = os.time(then_parts)
	local diff = now - then_

	local seconds = diff % 60
	diff = math.floor(diff / 60)
	local minutes = diff % 60
	diff = math.floor(diff / 60)
	local hours = diff % 24
	diff = math.floor(diff / 24)
	local days = diff % 30
	diff = math.floor(diff / 30)
	--local months = diff % 12
	--diff = math.floor(diff / 12)
	--local years = diff

	local months = now_parts.month - then_parts.month
	local years = now_parts.year - then_parts.year
	if months < 0 then
		months = months + 12
		years = years - 1
	end

	return {
		years = years,
		months = months,
		days = days,
		hours = hours,
		minutes = minutes,
		seconds = seconds,
	}
end

local function format_date(iso)
	local parsed = parse_iso(iso)
	if not parsed then
		return nil
	end
	return os.date('%e %B %Y', os.time(parsed))
end

local precision_levels = {
	years = 1,
	months = 2,
	days = 3,
	hours = 4,
	minutes = 5,
	seconds = 6,
}

local precision_index = {}
for k, v in pairs(precision_levels) do
	precision_index[v] = k
end

local plurals = {
	years   = { one = 'year',   other = 'years'   },
	months  = { one = 'month',  other = 'months'  },
	days    = { one = 'day',    other = 'days'    },
	hours   = { one = 'hour',   other = 'hours'   },
	minutes = { one = 'minute', other = 'minutes' },
	seconds = { one = 'second', other = 'seconds' },
}

local function format_age(iso, iso_now, precision)
	local prec_int = precision_levels[precision]
	if not prec_int then
		if not precision then
			prec_int = 6
		else
			return nil
		end
	end
	local parts = age(iso, iso_now)
	if not parts then
		return nil
	end
	local strs = {}
	for i = 1, prec_int do
		local part = parts[precision_index[i]]
		if part > 0 then
			local plural = plurals[precision_index[i]]
			strs[#strs + 1] = tostring(part)
				.. ' '
				.. plural[part == 1 and 'one' or 'other']
		end
	end
	return table.concat(strs, ', ')
end

local function age_mw(frame)
	local args = frame.args
	local iso = args[1]
	local iso_now = args[2]
	local precision = args[3]
	return format_age(iso, iso_now, precision)
end

local function date_mw(frame)
	local args = frame.args
	local iso = args[1]
	return format_date(iso)
end

local function retro_mw(frame)
	local args = frame.args
	local offset = tonumber(args[1])
	return retro(offset)
end

return {
	format_age = age_mw,
	format_date = date_mw,
	retro = retro_mw,
	age = age,
}