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() -- 2020.12.19: 由于服务端未知改动,本函数功能已失效,将默认返回表示东八区的时区信息。 if true then return 8, 0 else 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 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