- Welcome to Touhou Wiki!
- Registering is temporarily disabled. Check in our Discord server to request an account and for assistance of any kind.
Module:Timeconv
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Timeconv/doc
-- Time conversion module
-- by DennouNeko
-- Warning! This module is highly experimental!
-- It shouldn't be used for anything more than calculating approximate dates of events.
local common = require("Module:Common")
local libastro = require("Module:Lib astro")
local astro = libastro.astro
local time = libastro.time
local function mod(a, b)
return a - b * math.floor(a/b)
end
local function amod(a, b)
return mod(a-1, b) + 1
end
local function fulld(jd)
return math.floor(jd - 0.5) + 0.5
end
-- dir = true for North and East
local function gps_to_deg(d, m, s, dir)
return common.cv(dir, 1, -1) * ((s / 60 + m) / 60 + d)
end
local function deg_to_gps(deg)
local dir = common.cv(deg > 0, 1, -1)
deg = deg * dir
local d = math.floor(deg)
deg = (deg - d) * 60
local m = math.floor(deg)
deg = (deg - m) * 60
return d,m,deg,(dir>0)
end
local function gregorian_to_jd_test(frame)
local year,month,day = tonumber(frame.args['year']), tonumber(frame.args['month']), tonumber(frame.args['day'])
local hour = tonumber(frame.args['hour'])
local tz = tonumber(frame.args['timezone'])
return time.gregorian_to_jd(year, month, day, hour) - (tz / 24)
end
local function jd_to_gregorian_test(frame)
local jd = tonumber(frame.args['jd'])
local tz = tonumber(frame.args['timezone'])
local year,month,day = time.jd_to_gregorian(jd + (tz / 24))
return string.format("%i.%02u.%02u (%s))", year, month, day, time.wdays[time.jwday(jd + (tz / 24)) + 1])
end
local function gensokyo_to_jd_test(frame)
local season = tonumber(frame.args['season'])
local month = tonumber(frame.args['month'])
local day = tonumber(frame.args['day'])
local leap = month < 0
month = math.abs(month)
return time.gensokyo_to_jd(season, month, leap, day)
end
local function jd_to_gensokyo_test(frame)
local jd = tonumber(frame.args['jd'])
local tz = 9
local season,month,leap,day = time.jd_to_gensokyo(jd)
if leap then month = -month end
return string.format("%i/%u/%u (%s)", season, month, day, time.wdays[time.jwday(jd) + 1])
end
function time.timestamp_to_jd(ts)
-- convert days and add start of epoch
return ts / (60 * 60 * 24) + time.gregorian_to_jd(1970, 1, 1, 0)
end
function time.jd_to_timestamp(ts)
-- subtract start of epoch and convert to seconds
return (jd - time.gregorian_to_jd(1970, 1, 1, 0)) * (60 * 60 * 24)
end
local months = {'Deutzia Month', 'Planting Month', 'Month of Water', 'Book Month', 'Leaf Month', 'Long-lasting Month', 'Godless Month', 'Frost Month', 'Priest-running Month', 'Affection Month', 'More Clothes Month', 'Sprouting Month', 'Leap'}
local function season_to_elems(s)
s = s + 1
local n1 = {'sun', 'moon', 'star'}
local n2 = {'spring', 'summer', 'autumn', 'winter'}
local n3 = {'earth', 'fire', 'water', 'wood', 'metal'}
return n1[amod(s, 3)], n2[amod(s, 4)], n3[amod(s, 5)]
end
local function season_test(frame)
local ret = {}
local starts = tonumber(frame.args['start'])
local i
ret[#ret+1] = '<table class="wikitable">'
ret[#ret+1] = '<tr>'
for i=0,18 do
ret[#ret+1] = '<td>' .. (starts + i) .. '</td>'
end
ret[#ret+1] = '</tr>'
ret[#ret+1] = '<tr>'
for i=0,18 do
ret[#ret+1] = '<td>' .. common.cv(time.gensokyo_leap(starts + i), '<span style="color:#ff0000; font-weight: bold;">yes</span>', 'no') .. '</td>'
end
ret[#ret+1] = '</tr>'
ret[#ret+1] = '</table>'
return table.concat(ret, '\n')
end
local function test_month(frame)
local season = tonumber(frame.args['season'])
local s1,m1,l1,d1
local month = 1
local jd = time.gensokyo_to_jd(season, 1, false, 1)
local jd1 = jd - 1
ret = {}
ret1 = {}
ret[#ret+1] = '\n* ' .. common.cv(time.gensokyo_leap(season), '<span style="color:#ff0000; font-weight: bold;">' .. season .. '</span>', season) .. string.format(', season of %s, %s and %s', season_to_elems(season))
ret[#ret+1] = '<table class="wikitable">'
ret[#ret+1] = '<tr><th>month:</th>'
ret1[#ret1+1] = '<tr><th>days:</th>'
repeat
s1,m1,l1,d1 = time.jd_to_gensokyo(jd)
if s1 ~= season then break end
jd1 = astro.gensokyo_new_moon_on_or_after(jd + 1)
mc = common.cv(time.gensokyo_leap(season), 13, 12)
ret[#ret+1] = '<td>' .. common.cv(l1, '<span style="color:#ff0000; font-weight: bold;">' .. (-m1) .. '</span>', m1) .. '</td>'
ret1[#ret1+1] = '<td>' .. (jd1-jd) .. '</td>'
jd = jd1
month = month + 1
until(month > 13)
ret1[#ret1+1] = '</tr>'
ret[#ret+1] = '</tr>'
ret[#ret+1] = table.concat(ret1, '\n')
ret[#ret+1] = '</table>'
return table.concat(ret, '\n')
end
local function test_calendar(frame)
local jd, jd1, jd2
local i, j
local month = tonumber(frame.args['month'])
local day = tonumber(frame.args['day'])
if month == nil then month = 1 end
if day == nil then day = 1 end
local leap = false
local mark = common.isset(frame.args['mark'])
local align = frame.args['align']
if month < 0 then
leap = true
month = -month
end
if common.isset(frame.args['season']) then
jd2 = time.gensokyo_to_jd(tonumber(frame.args['season']), month, leap, day)
elseif common.isset(frame.args['year']) then
jd2 = time.gregorian_to_jd(tonumber(frame.args['year']), month, day, 0)
else
return '<span style="color:#ff0000; font-weight: bold;">Error: test_calendar:</span> Calendar requires a season or year param!'
end
jd = astro.gensokyo_new_moon_before(jd2+1)
jd1 = astro.gensokyo_new_moon_on_or_after(jd+1)
local gs,gm,gl,gd = time.jd_to_gensokyo(jd)
local n1,n2,n3 = season_to_elems(gs)
local eph = {}
eph[1] = time.standard_from_universal(astro.lunar_phase_after( 0, jd - 1), time.location(jd))
eph[2] = time.standard_from_universal(astro.lunar_phase_after( 90, jd - 1), time.location(jd))
eph[3] = time.standard_from_universal(astro.lunar_phase_after(180, jd - 1), time.location(jd))
eph[4] = time.standard_from_universal(astro.lunar_phase_after(270, jd - 1), time.location(jd))
jd = time.standard_from_universal(jd, time.location(jd))
jd1 = time.standard_from_universal(jd1, time.location(jd1))
jd2 = time.standard_from_universal(jd2, time.location(jd2))
local ret = {}
if common.isset(align) then
if align == 'left' then
ret[#ret+1] = '<div style="float: left; clear: left;">'
elseif align == 'right' then
ret[#ret+1] = '<div style="float: right; clear: right;">'
else
align = nil
end
end
ret[#ret+1] = '<table class="wikitable">'
ret[#ret+1] = '<caption>'
ret[#ret+1] = string.format("'''%i''' - %s, %s and %s", gs, n1, n2, n3)
ret[#ret+1] = '<br/>' .. string.format("%i - %s%s", gm, common.cv(gl, months[13] .. ' ', ''), months[gm])
ret[#ret+1] = '</caption>'
ret[#ret+1] = '<tr><th style="width: 30px">Mon</th><th style="width: 30px">Tue</th><th style="width: 30px">Wed</th><th style="width: 30px">Thu</th><th style="width: 30px">Fri</th><th style="width: 30px">Sat</th><th style="width: 30px; color:#ff0000">Sun</th></tr>'
ret[#ret+1] = '<tr>'
local wd0 = time.jwday(jd) + 1
if wd0 > 1 then
for i=1,(wd0-1) do
ret[#ret+1] = '<td> </td>'
end
end
local days = math.floor(jd1-jd)
for i=1,days do
ret[#ret+1] = '<td' .. common.cv(mark and math.abs(jd2 - (jd + i - 1)) < 1, ' style="background-color: #ffe0e0;"', '') .. '>'
ret[#ret+1] = common.cv(wd0 == 7, '<span style="color:#ff0000; font-weight: bold;">' .. i .. '</span>', i)
for j=1,4 do
if math.abs(eph[j] - (jd + i - 1)) <= 0.5 then
ret[#ret+1] = string.format('<sup>%u</sup>', j)
end
end
ret[#ret+1] = '</td>'
wd0 = amod(wd0 + 1, 7)
if (wd0 == 1) and (i < days) then
ret[#ret+1] = '</tr><tr>'
end
end
if wd0 > 1 then
for i=wd0,7 do
ret[#ret+1] = '<td> </td>'
end
end
if common.isset(align) then
ret[#ret+1] = '</div>'
end
ret[#ret+1] = '</table>'
return table.concat(ret)
end
local function gensokyo_to_gregorian(frame)
local season = tonumber(frame.args[1])
local month = tonumber(frame.args[2])
local leap = false
local day = tonumber(frame.args[3])
local approx = false
if (season == nil) or (month == nil) then
return frame:preprocess('<span style="color:#ff0000; font-weight: bold;">[[Module:Timeconv]] gen_to_greg error:</span> season and month params are required.')
end
if day == nil then
approx = true
day = 1
end
if month < 0 then
month = -month
leap = true
end
-- shift in case that uzuki = 4th month
if common.isset(frame.args['shift']) then
month = amod(month + 9, 12) -- + 12 - 3
end
local jd = time.gensokyo_to_jd(season, month, leap, day)
local y,m,d = time.jd_to_gregorian(jd)
-- the actual date formatting
return common.cv(approx, '~', '') .. string.format("%i/%02u/%02u", y, m, d)
end
-- Assumes uzuki is 4th month
local months_dict = {
['Mutsuki'] = 1,
['Kisaragi'] = 2,
['Yayoi'] = 3,
['Uzuki'] = 4,
['Satsuki'] = 5,
['Minazuki'] = 6,
['Fumizuki'] = 7,
['Hazuki'] = 8,
['Nagatsuki'] = 9,
['Kannazuki'] = 10,
['Shimotsuki'] = 11,
['Shiwasu'] = 12
}
-- {{timeconv | news_estimate | 124 | Hazuki}} => "est. 2009/09/19 ~ 2009/10/18"
local function news_estimate(frame)
local season = tonumber(frame.args[1])
local month = months_dict[frame.args[2]]
if (season == nil) or (month == nil) then
return frame:preprocess('<span style="color:#ff0000; font-weight: bold;">[[Module:Timeconv]] news_estimate error:</span> season and month params are required.')
end
-- shift: uzuki is 4th month
month = ((month - 3) - 1) % 12 + 1
if (month >= 10) then -- shifted to prev year in calcs, which assume uzuki=1
season = season - 1
end
-- get next month for range end
local next_season = (month == 12) and season+1 or season
local next_month = month % 12 + 1
local jd = time.gensokyo_to_jd(season, month, false, 1)
local next_jd = time.gensokyo_to_jd(next_season, next_month, false, 1)
-- date formatting
return 'est. ' .. string.format('%i/%02u/%02u', time.jd_to_gregorian(jd)) .. ' ~ ' .. string.format('%i/%02u/%02u', time.jd_to_gregorian(next_jd))
end
local function gregorian_to_gensokyo(frame)
local year = tonumber(frame.args[1])
local month = tonumber(frame.args[2])
local day = tonumber(frame.args[3])
local approx = false
if (year == nil) or (month == nil) then
return frame:preprocess('<span style="color:#ff0000; font-weight: bold;">[[Module:Timeconv]] greg_to_gen error:</span> year and month params are required.')
end
if day == nil then
day = 1
approx = true
end
local jd = time.gregorian_to_jd(year, month, day, 0)
local gs,gm,gl,gd = time.jd_to_gensokyo(jd)
-- shift in case that uzuki = 4th month
if common.isset(frame.args['shift']) then
gm = amod(gm + 3, 12)
end
if gl then
gm = -gm
end
-- the actual date formatting
return common.cv(approx, '~', '') .. string.format("%i/%i/%u", gs, gm, gd)
end
return {
['gregorian_to_jd'] = gregorian_to_jd_test,
['jd_to_gregorian'] = jd_to_gregorian_test,
['gensokyo_to_jd'] = gensokyo_to_jd_test,
['jd_to_gensokyo'] = jd_to_gensokyo_test,
['season_test'] = season_test,
['test_month'] = test_month,
['gen_to_greg'] = gensokyo_to_gregorian,
['news_estimate'] = news_estimate,
['greg_to_gen'] = gregorian_to_gensokyo,
['calendar'] = test_calendar,
}
-- [[Category:Lua Scripts|{{PAGENAME}}]]