Module:TimeUtil

From Leaguepedia | League of Legends Esports Wiki
Jump to: navigation, search

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

local lang = mw.getLanguage('en')
local util_table = require('Module:TableUtil')
local util_vars = require("Module:VarsUtil")
local Date = require('Module:Date')
local SECONDS_IN_DAY = 24 * 60 * 60

local TZLIST = { 'PST', 'CET', 'KST', 'UTC' }
local DAYS_PER_WEEK = 7

local h = {}

function h.printDelta(delta)
	return delta > 0 and ('+' .. delta) or delta
end

local p = {}

p.monthNumberToTri = { 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' }

p.monthNumberToName = { 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' }

p.monthNameToNumber = util_table.hash(p.monthNumberToName)

p.toUTC = {
	[true] = { PST = 7, CET = -2, KST = -9, UTC = 0 },
	[false] = { PST = 8, CET = -1, KST = -9, UTC = 0 },
	yes = { PST = 7, CET = -2, KST = -9, UTC = 0 },
	no = { PST = 8, CET = -1, KST = -9, UTC = 0 },
	spring = { PST = 7, CET = -1, KST = -9, UTC = 0 },
	fall = { PST = 7, CET = -1, KST = -9, UTC = 0 },
}

function p.strToTime(str)
	local year, month, day, hour, minute, second = string.match(str, "(%d%d%d%d)%-(%d%d)%-(%d%d) (%d%d):(%d%d):?(%d?%d?)")
	return {
		year = year,
		month = month,
		day = day,
		hour = hour, 
		min = minute,
		sec = second
	}
end

function p.strToDate(str)
	local year, month, day = string.match(str, "(%d%d%d%d)-(%d%d)-(%d%d)")
	return {
		year = year,
		month = month,
		day = day
	}
end

function p.strToDateStr(str)
	if not str then return nil end
	local date = str:match("(%d%d%d%d%-%d%d%-%d%d)")
	return date
end

function p.strToDateStrAllowYearOnly(str)
	local date = p.strToDateStr(str)
	if date then return date end
	local year = str:match("(%d%d%d%d)%-")
	return year
end

function p.strToTimeStr(str)
	if not str then return nil end
	return str:match('%d%d:%d%d')
end

function p.strToDateFuzzy(str)
	local year, month, day = str:match('(....)-(..)-(..)')
	return {
		year = tonumber(year),
		month = tonumber(month),
		day = tonumber(day)
	}
end

function p.strToYearNumber(str)
	if not str then return nil end
	local year = str:match('(%d%d%d%d)%-')
	if not year then return nil end
	return tonumber(year)
end

function p.strToDateStrFuzzy(str, isApprox)
	local year, month, day = str:match('(....)%-(..)%-(..)')
	if not year and not month and not day then
		error(('Bad fuzzy date: %s'):format(str))
	end
	year = tonumber(year)
	month = tonumber(month)
	day = tonumber(day)
	local suffix = isApprox and ' (approx.)' or ''
	if not month and not day then
		return year .. suffix
	elseif not day then
		return lang:formatDate('F Y', ('%s-%s-01'):format(year, month))  .. suffix
	end
	return lang:formatDate('j F Y', str) .. suffix
end

function p.strToDateStrFuzzyWithoutYear(str, isApprox)
	local year, month, day = str:match('(....)%-(..)%-(..)')
	if not year and not month and not day then
		error(('Bad fuzzy date: %s'):format(str))
	end
	year = tonumber(year)
	month = tonumber(month)
	day = tonumber(day)
	local suffix = isApprox and ' (approx.)' or ''
	if not year then return 'Unknown date' end
	if not month and not day then
		return year .. suffix
	elseif not day then
		return lang:formatDate('F', ('%s-%s-01'):format(year, month))  .. suffix
	end
	return lang:formatDate('F j', str) .. suffix
end

function p.isInFuture(str, intervalSeconds)
	if not intervalSeconds then intervalSeconds = 0 end
	return os.difftime(os.time(p.strToTime(str)),os.time()) > intervalSeconds
end

function p.dateIsInFuture(str, intervalSeconds)
	if not intervalSeconds then intervalSeconds = 0 end
	local time = p.strToDateFuzzy(str)
	if time.day == '??' then time.day = 31 end
	if time.month == '??' then time.month = 12 end
	return os.difftime(os.time(time),os.time()) > intervalSeconds
end

function p.dateIsInFutureOrNow(str, intervalSeconds)
	local time = p.strToDateFuzzy(str)
	if time.day == '??' then time.day = 31 end
	if time.month == '??' then time.month = 12 end
	return os.difftime(os.time(time),os.time()) > -1 / 2 * SECONDS_IN_DAY
end

function p.dateInLocal(str)
	local tbl = mw.html.create('span'):addClass('DateInLocal'):wikitext(lang:formatDate('Y,n,d,H,i', str))
	return tostring(tbl)
end

function p.dateOnlyInLocal(str)
	local tbl = mw.html.create('span'):addClass('DateOnlyInLocal'):wikitext(lang:formatDate('Y,n,d,H,i', str))
	return tostring(tbl)
end

function p.dateInLocalMatches(str)
	local tbl = mw.html.create('span'):addClass('DateInLocalMatches'):wikitext(lang:formatDate('Y,n,d,H,i', str))
	return tostring(tbl)
end

function p.timeInLocal(str)
	local tbl = mw.html.create('span'):addClass('TimeInLocal'):wikitext(lang:formatDate('Y,n,d,H,i', str))
	return tostring(tbl)
end

function p.countdown(str, args)
	if not args then args = {} end
	local i = args.i or ''
	local data_end = args.data_end or 'remove'
	local options = args.options and table.concat(args.options, ' ') or 'no-leading-zeros'
	local tbl = mw.html.create()
	tbl:tag('span')
		:attr('data-end', data_end)
		:attr('data-options',options)
		:attr('data-toggle','.post-countdown' .. i)
		:addClass('countdown')
		:css('display','none')
		:tag('span')
			:addClass('countdowndate')
			:wikitext(lang:formatDate('j F Y H:i:s', str) .. ' +0000')
	tbl:tag('span')
		:addClass('post-countdown' .. i)
		:css('display','none')
		:wikitext(args.default or '-')
	return tostring(tbl)
end

function p.unix(str)
	if type(str) == 'table' then
		str = p.strFromTable(str)
	end
	return lang:formatDate('U', str)
end

function p.unixNumber(str)
	if not str then return nil end
	return tonumber(p.unix(str))
end

function p.age(bday, death)
	if type(bday) == 'string' then
		bday = p.strToDate(bday)
	end
	for k, v in pairs(bday) do
		bday[k] = tonumber(v)
	end
	if type(death) == 'string' then
		death = p.unixNumber(death)
	end
	if not bday.year or not bday.month or not bday.day then return end
	local now = os.date('*t', death)
	local bdaypast = now.month > bday.month or now.month == bday.month and now.day >= bday.day
	return now.year - bday.year - 1 + (bdaypast and 1 or 0)
end

function p.getTimezones(str, init_tz, dst)
	if type(dst) == 'string' then
		dst = dst:lower()
	end
	if not p.toUTC[dst] then
		error(('Invalid timezone value of %s. Allowed values: yes, no, spring, fall.'):format(dst))
	end
	local delta = p.toUTC[dst][init_tz]
	local utc = lang:formatDate('Y-m-d H:i', ('%s %s hours'):format(str, h.printDelta(delta)))
	local tbl = { UTC = utc }
	for _, v in pairs(TZLIST) do
		delta = -1 * p.toUTC[dst][v]
		tbl[v] = lang:formatDate('Y-m-d H:i', ('%s %s hours'):format(utc, h.printDelta(delta)))
	end
	tbl.UTC = utc
	return tbl
end

function p.addTimezonesToRowFromUTC(row)
	-- overwrite a row's timezones to add PST, KST, and CET
	local timezones = p.getTimezones(row.UTC, 'UTC', row.DST)
	util_table.merge(row, timezones)
end

function p.strFromTable(dt, format)
	local str = os.date('%Y-%m-%d', os.time(dt))
	if not format then return str end
	return lang:formatDate(format, str)
end

function p.getDatesInAWeek(date)
	local sunday = lang:formatDate('Y-m-d', ('%s - %s days'):format(
		date,
		lang:formatDate('w', date)
	))
	local tbl = {}
	for offset = 0, DAYS_PER_WEEK - 1 do
		tbl[#tbl+1] = lang:formatDate('Y-m-d', ('%s + %s days'):format(sunday, offset))
	end
	return tbl
end

return p