No edit summary |
No edit summary |
||
(2 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
local lang = mw.getLanguage('en') |
local lang = mw.getLanguage('en') |
||
local util_table = require('Module:TableUtil') |
local util_table = require('Module:TableUtil') |
||
+ | local util_vars = require("Module:VarsUtil") |
||
local Date = require('Module:Date') |
local Date = require('Module:Date') |
||
local SECONDS_IN_DAY = 24 * 60 * 60 |
local SECONDS_IN_DAY = 24 * 60 * 60 |
||
− | local TZLIST = { 'PST', 'CET', 'KST' } |
+ | local TZLIST = { 'PST', 'CET', 'KST', 'UTC' } |
+ | local DAYS_PER_WEEK = 7 |
||
local h = {} |
local h = {} |
||
Line 21: | Line 23: | ||
p.toUTC = { |
p.toUTC = { |
||
− | [true] = { PST = 7, CET = -2, KST = -9 }, |
+ | [true] = { PST = 7, CET = -2, KST = -9, UTC = 0 }, |
− | [false] = { PST = 8, CET = -1, KST = -9 }, |
+ | [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) |
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)") |
+ | 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 { |
return { |
||
year = year, |
year = year, |
||
Line 52: | Line 56: | ||
local date = str:match("(%d%d%d%d%-%d%d%-%d%d)") |
local date = str:match("(%d%d%d%d%-%d%d%-%d%d)") |
||
return date |
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 |
end |
||
Line 60: | Line 71: | ||
function p.strToDateFuzzy(str) |
function p.strToDateFuzzy(str) |
||
− | local year, month, day = str:match('( |
+ | local year, month, day = str:match('(....)-(..)-(..)') |
return { |
return { |
||
− | year = year, |
+ | year = tonumber(year), |
− | month = month, |
+ | month = tonumber(month), |
− | day = day |
+ | 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 |
end |
||
Line 131: | Line 184: | ||
function p.unix(str) |
function p.unix(str) |
||
+ | if type(str) == 'table' then |
||
+ | str = p.strFromTable(str) |
||
+ | end |
||
return lang:formatDate('U', str) |
return lang:formatDate('U', str) |
||
end |
end |
||
Line 139: | Line 195: | ||
end |
end |
||
− | function p.age(bday) |
+ | function p.age(bday, death) |
if type(bday) == 'string' then |
if type(bday) == 'string' then |
||
bday = p.strToDate(bday) |
bday = p.strToDate(bday) |
||
Line 146: | Line 202: | ||
bday[k] = tonumber(v) |
bday[k] = tonumber(v) |
||
end |
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 bdaypast = now.month > bday.month or now.month == bday.month and now.day >= bday.day |
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) |
return now.year - bday.year - 1 + (bdaypast and 1 or 0) |
||
Line 152: | Line 212: | ||
function p.getTimezones(str, init_tz, dst) |
function p.getTimezones(str, init_tz, dst) |
||
+ | if type(dst) == 'string' then |
||
+ | dst = dst:lower() |
||
+ | end |
||
if not p.toUTC[dst] then |
if not p.toUTC[dst] then |
||
error(('Invalid timezone value of %s. Allowed values: yes, no, spring, fall.'):format(dst)) |
error(('Invalid timezone value of %s. Allowed values: yes, no, spring, fall.'):format(dst)) |
||
end |
end |
||
local delta = p.toUTC[dst][init_tz] |
local delta = p.toUTC[dst][init_tz] |
||
− | local utc = lang:formatDate('Y- |
+ | local utc = lang:formatDate('Y-m-d H:i', ('%s %s hours'):format(str, h.printDelta(delta))) |
local tbl = { UTC = utc } |
local tbl = { UTC = utc } |
||
for _, v in pairs(TZLIST) do |
for _, v in pairs(TZLIST) do |
||
delta = -1 * p.toUTC[dst][v] |
delta = -1 * p.toUTC[dst][v] |
||
− | tbl[v] = lang:formatDate('Y- |
+ | tbl[v] = lang:formatDate('Y-m-d H:i', ('%s %s hours'):format(utc, h.printDelta(delta))) |
end |
end |
||
tbl.UTC = utc |
tbl.UTC = utc |
||
return tbl |
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 |
end |
||
Line 170: | Line 239: | ||
if not format then return str end |
if not format then return str end |
||
return lang:formatDate(format, str) |
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 |
end |
||
Latest revision as of 17:06, 27 December 2020
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