Module:TimeZone

H萌娘,万物皆可H的百科全书!
跳到导航 跳到搜索
Template-info.svg 模块文档  [创建] [刷新]
local module = {}

function module.getTimeZone(frame)
    local hour, minute = normalize(frame.args[1])
    local timezone = timeZoneToString(hour, minute)
    
    local output = frame.args["output"]
    if output == "number" then
        return timezone
    elseif output == "utc" then
        return "UTC"..timezone
    elseif output == "text" then
        if timezone == "+00:00" then
            return "零时区"
        else
            local left, middle
            
            --当时间差超过±12小时,在计算时区是必须调整至±12小时的范围内。
            local hour = math.fmod(hour, 24)
            local abs_hour = math.abs(hour)
            local sign = hour / abs_hour
            if abs_hour > 12 or (abs_hour == 12 and minute > 0) then
                hour = 24 - abs_hour
                if minute ~= 0 then
                    hour = hour - 1
                    minute = 60 - minute
                end
                hour = -sign * hour
            end
            
            if hour < 0 then
                left = "西"
            else
                left = "东"
            end
            
            local texts = {"一","二","三","四","五","六","七","八","九","十","十一","十二"}
            middle = texts[math.abs(tonumber(hour))]
            
            return left..middle.."区"
        end
    end
end

function module.convert(frame)
    local args = frame.args
    
    local year = tonumber(args["year"])
    local month = tonumber(args["month"])
    local day = tonumber(args["day"])
    local hour = tonumber(args["hour"]) or 12
    local minute = tonumber(args["minute"]) or 0
    local second = tonumber(args["second"]) or 0
    
    local o_hour, o_minute = normalize(args["o_timezone"])
    local c_hour, c_minute = normalize(args["c_timezone"])
    local o_sign, c_sign
    if o_hour >= 0 then o_sign = 1 else o_sign = -1 end
    if c_hour >= 0 then c_sign = 1 else c_sign = -1 end
    
    local difftime = (c_hour * 3600 + o_sign * c_minute * 60) -
                     (o_hour * 3600 + c_sign * o_minute * 60)
    
    local o_time = { year = year, month = month, day = day, hour = hour, min = minute, sec = second }
    local c_time = os.date("*t", os.time(o_time) + difftime)
    
    local text = args[1] or ""
    --剥离nowiki标签。
    text = mw.text.unstripNoWiki(text)
    text = mw.text.decode(text)
    
    --格式化日期
    c_time['timezone'] = {c_hour, c_minute}
    text = formatDate(text, c_time)
    
    --生成能解析wiki文本的字符串。
    text = frame:preprocess(text)
    
    return text
end

function module.formatList(frame)
    local var_array = require("Module:Var-array")
    local formatList = {}
    for i, item in ipairs(getFormat()) do
        table.insert(formatList, { item.format, item.description })
    end
    var_array.new("timezone.convert.formatlist", formatList)
end

function getFormat()
    return {
        {
            format = "%(y)",
            description = "不包含纪元的年份。如果不包含纪元的年份小于10,则显示不具有前导零的年份。",
            callback = function(matched_times, time) return tostring(tonumber(string.sub(tostring(time.year), -2))) end
        },
        {
            format = "%y",
            description = "不包含纪元的年份。如果不包含纪元的年份小于10,则显示不具有前导零的年份。<code>%(y)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(tonumber(string.sub(tostring(time.year), -2))) end
        },
        {
            format = "%(yy)",
            description = "不包含纪元的年份。如果不包含纪元的年份小于10,则显示具有前导零的年份。",
            callback = function(matched_times, time) return string.format("%02d", tonumber(string.sub(tostring(time.year), -2))) end
        },
        {
            format = "%(yyyy)",
            description = "包括纪元的四位数的年份。",
            callback = function(matched_times, time) return tostring(time.year) end
        },
        {
            format = "%(gg)",
            description = "时期或纪元。如果要设置格式的日期不具有关联的时期或纪元字符串,则忽略该模式。",
            callback = function(matched_times, time) return tostring((tonumber(time.year) - tonumber(string.sub(tostring(time.year), -2))) / 100) end
        },
        {
            format = "%(M)",
            description = "月份数字。一位数的月份没有前导零。",
            callback = function(matched_times, time) return tostring(tonumber(time.month)) end
        },
        {
            format = "%M",
            description = "月份数字。一位数的月份没有前导零。<code>%(M)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(tonumber(time.month)) end
        },
        {
            format = "%(MM)",
            description = "月份数字。一位数的月份有一个前导零。",
            callback = function(matched_times, time) return string.format("%02d", (tonumber(time.month))) end
        },
        {
            format = "%(MMM)",
            description = "月份的缩写名称。",
            callback = function(matched_times, time)
                local AbbreviatedMonthNames = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" }
                return AbbreviatedMonthNames[tonumber(time.month)]
            end
        },
        {
            format = "%(MMMM)",
            description = "月份的缩写名称。",
            callback = function(matched_times, time)
                local AbbreviatedMonthNames = { "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" }
                return AbbreviatedMonthNames[tonumber(time.month)].."月"
            end
        },
        {
            format = "%(D)",
            description = "年中的某一天。",
            callback = function(matched_times, time)
                t1 = { year = time.year, month = time.month, day = time.day, hour = 0, min = 0, sec = 0 }
                t2 = { year = time.year, month = 1, day = 1, hour = 0, min = 0, sec = 0 }
                return tostring(math.floor(os.difftime(os.time(t1), os.time(t2)) / 86400))
            end
        },
        {
            format = "%D",
            description = "年中的某一天。<code>%(D)</code>的简略写法。",
            callback = function(matched_times, time)
                t1 = { year = time.year, month = time.month, day = time.day, hour = 0, min = 0, sec = 0 }
                t2 = { year = time.year, month = 1, day = 1, hour = 0, min = 0, sec = 0 }
                return tostring(math.floor(os.difftime(os.time(t1), os.time(t2)) / 86400))
            end
        },
        {
            format = "%(DD)",
            description = "这一年共有多少天。",
            callback = function(matched_times, time)
                t1 = { year = time.year + 1, month = 1, day = 1, hour = 0, min = 0, sec = 0 }
                t2 = { year = time.year, month = 1, day = 1, hour = 0, min = 0, sec = 0 }
                return tostring(math.floor(os.difftime(os.time(t1), os.time(t2)) / 86400))
            end
        },
        {
            format = "%(d)",
            description = "月中的某一天。一位数的日期没有前导零。",
            callback = function(matched_times, time) return tostring(tonumber(time.day)) end
        },
        {
            format = "%d",
            description = "月中的某一天。一位数的日期没有前导零。<code>%(d)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(tonumber(time.day)) end
        },
        {
            format = "%(dd)",
            description = "月中的某一天。一位数的日期有一个前导零。",
            callback = function(matched_times, time) return string.format("%02d", tonumber(time.day)) end
        },
        {
            format = "%(w)",
            description = "周中的某一天。",
            callback = function(matched_times, time) return tostring(tonumber(time.wday)) end
        },
        {
            format = "%w",
            description = "周中的某一天。<code>%(w)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(tonumber(time.wday)) end
        },
        {
            format = "%(ww)",
            description = "周中某天的缩写名称。",
            callback = function(matched_times, time)
                local wday = tonumber(time.wday)
                return mw.ustring.sub("日一二三四五六", wday, wday)
            end
        },
        {
            format = "%(www)",
            description = "周中某天的缩写名称。",
            callback = function(matched_times, time)
                local wday = tonumber(time.wday)
                return "星期"..mw.ustring.sub("日一二三四五六", wday, wday)
            end
        },
        {
            format = "%(h)",
            description = "12 小时制的小时。一位数的小时数没有前导零。",
            callback = function(matched_times, time) return tostring(math.fmod(tonumber(time.hour), 12)) end
        },
        {
            format = "%h",
            description = "12 小时制的小时。一位数的小时数没有前导零。<code>%(h)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(math.fmod(tonumber(time.hour), 12)) end
        },
        {
            format = "%(hh)",
            description = "12 小时制的小时。一位数的小时数有一个前导零。",
            callback = function(matched_times, time) return string.format("%02d", math.fmod(tonumber(time.hour), 12)) end
        },
        {
            format = "%(H)",
            description = "24 小时制的小时。一位数的小时数没有前导零。",
            callback = function(matched_times, time) return tostring(tonumber(time.hour)) end
        },
        {
            format = "%H",
            description = "24 小时制的小时。一位数的小时数没有前导零。<code>%(H)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(tonumber(time.hour)) end
        },
        {
            format = "%(HH)",
            description = "24 小时制的小时。一位数的小时数有一个前导零。",
            callback = function(matched_times, time) return string.format("%02d", tonumber(time.hour)) end
        },
        {
            format = "%(m)",
            description = "分钟。一位数的分钟数没有前导零。",
            callback = function(matched_times, time) return tostring(tonumber(time.min)) end
        },
        {
            format = "%m",
            description = "分钟。一位数的分钟数没有前导零。<code>%(m)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(tonumber(time.min)) end
        },
        {
            format = "%(mm)",
            description = "分钟。一位数的分钟数有一个前导零。",
            callback = function(matched_times, time) return string.format("%02d", tonumber(time.min)) end
        },
        {
            format = "%(s)",
            description = "秒。一位数的秒数没有前导零。",
            callback = function(matched_times, time) return tostring(tonumber(time.sec)) end
        },
        {
            format = "%s",
            description = "秒。一位数的秒数没有前导零。<code>%(s)</code>的简略写法。",
            callback = function(matched_times, time) return tostring(tonumber(time.sec)) end
        },
        {
            format = "%(ss)",
            description = "秒。一位数的秒数有一个前导零。",
            callback = function(matched_times, time) return string.format("%02d", tonumber(time.sec)) end
        },
        {
            format = "%(sss)",
            description = "Unix时间戳(Unix timestamp)。从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。",
            callback = function(matched_times, time) return tostring(os.time(time)) end
        },
        {
            format = "%(t)",
            description = "一天中时间段的更加详细的提示信息。",
            callback = function(matched_times, time)
                local hour = tonumber(time.hour)
                if hour < 12 then return "上午"
                else return "下午"
                end
            end
        },
        {
            format = "%t",
            description = "一天中时间段的更加详细的提示信息。<code>%(t)</code>的简略写法。",
            callback = function(matched_times, time)
                local hour = tonumber(time.hour)
                if hour < 12 then return "上午"
                else return "下午"
                end
            end
        },
        {
            format = "%(tt)",
            description = "一天中时间段的更加详细的提示信息。",
            callback = function(matched_times, time)
                local hour = tonumber(time.hour)
                if hour < 7 then return "凌晨"
                elseif hour < 11 then return "上午"
                elseif hour < 13 then return "中午"
                elseif hour < 17 then return "下午"
                elseif hour < 20  then return "傍晚"
                elseif hour < 22 then return "晚上"
                else return "深夜"
                end
            end
        },
        {
            format = "%(z)",
            description = "时区偏移量(“+”或“-”后面仅跟小时)。一位数的小时数没有前导零。例如,太平洋标准时间是“-8”。",
            callback = function(subStr, time)
                local hour, minute = time.timezone[1], time.timezone[2]
                if hour >= 0 then return "+"..hour
                else return tostring(hour)
                end
            end
        },
        {
            format = "%z",
            description = "时区偏移量(“+”或“-”后面仅跟小时)。一位数的小时数没有前导零。例如,太平洋标准时间是“-8”。<code>%(z)</code>的简略写法。",
            callback = function(subStr, time)
                local hour, minute = time.timezone[1], time.timezone[2]
                if hour >= 0 then return "+"..hour
                else return tostring(hour)
                end
            end
        },
        {
            format = "%(zz)",
            description = "时区偏移量(“+”或“-”后面仅跟小时)。一位数的小时数有前导零。例如,太平洋标准时间是“-08”。",
            callback = function(subStr, time)
                local hour, minute = time.timezone[1], time.timezone[2]
                if hour >= 0 then return string.format("+%02d", hour)
                else return string.format("-%02d", -hour)
                end
            end
        },
        {
            format = "%(zzz)",
            description = "完整时区偏移量(“+”或“-”后面跟有小时和分钟)。一位数的小时数和分钟数有前导零。例如,太平洋标准时间是“-08:00”。",
            callback = function(subStr, time) 
                mw.log('zzzzz')
                return timeZoneToString(time.timezone[1], time.timezone[2]) 
            end
        },
        {
            format = "%(%)",
            description = "表示字符“%”。",
            callback = function(matched_times, time) return "%" end
        },
        {
            format = "%%",
            description = "表示字符“%”。<code>%(%)</code>的简略写法。",
            callback = function(matched_times, time) return "%" end
        }
    }
end

function formatDate(text, timeInfo)
    local FormatString = require("Module:FormatString")
    local tree = FormatString.buildTrie(getFormat())
    text = FormatString.replaceStr(text, tree, timeInfo)
    return text
end

function normalize(timezone)
    if timezone == nil or #timezone == 0 then
        return currentTimeZone() --用户当前时区
    else
        local hour, minute = mw.ustring.match(mw.text.trim(timezone), "^([-%+]?%d+):?(%d*)$")
        if hour == nil then
            error("时区参数格式不正确。")
        end
        return tonumber(hour), tonumber(minute) or 0
    end
end

function currentTimeZone()
    local a = os.date('!*t',os.time())--中时区的时间
    local b = os.date('*t',os.time())
    local seconds = os.difftime(os.time(b), os.time(a))
    
    local hour = math.floor(math.abs(seconds) / 3600)
    local minute = math.floor((math.abs(seconds) - hour * 3600) / 60)
    if seconds < 0 then
        hour = -hour
        if minute ~= 0 then
            minute = 60 - minute
        end
    end
    
    return hour, minute
end

function timeZoneToString(hour, minute)
    if minute == nil then minute = 0 end
    if hour >= 0 then
        return mw.ustring.format("+%02d:%02d", hour, minute)
    else
        return mw.ustring.format("-%02d:%02d", math.abs(hour), minute)
    end
end

return module