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