模块:模糊时间

来自有兽档案馆
文档图示 模块文档[创建] [跳转到代码]

本模块还没有文档页面。

您可以创建文档以让编者更好地理解本模块的用途。
编者可以在本模块的沙盒创建 | 镜像和测试样例创建页面进行实验。
请将模块自身所属的分类添加在文档中。本模块的子页面
local module = {}
local getArgs = require('Module:Arguments').getArgs
--本模块用于解析任意时间文本,并选择任意的格式化形式。
--要注意,时间文本并非一种精确的数值,而是包含着模糊性、连续性的描述。
--初步将模糊理解为单位层级。
--要将时间文本的模糊记录下来。如果没有格式化要求,那么应当保留这种模糊性。
--格式化的要求允许指定某主要单位下显示/不显示,指定主要单位的首选、必选显示单位,指定次序。允许更改时区、进行计算。
--正常的格式化要求下不应该改变信息含量
--一个合法的时间必须有确定的c模糊度,确切的说应当是一个连续无中断信息。

--支持ISO 8601

--辅助处理
function string.findAny(text,patterns,index)
	index=index or 1
	for	_,pattern in ipairs(patterns) do
		local b,e=text:find(pattern,index)
		if b then
			return b,e
		end
	end
	return false
end

local FormatString = {}

function string.buildTrie(formats)
	root = {}
	root.next = {}
	for _, format in ipairs(formats) do
		for i, item in ipairs(format) do
			if item.format then
				local cur = root
				for i = 1, mw.ustring.len(item.format), 1 do 
					local c = mw.ustring.sub(item.format, i, i)
					if cur.next[c] == nil then
						cur.next[c] = {} -- new node
						cur.next[c].next = {} 
						cur.next[c].father = cur
						cur.next[c].char = c
					end
					cur = cur.next[c]
				end
				cur.item = item
				cur.len = mw.ustring.len(item.format)
			end
		end
	end
	root.fail = {}
	local q = require("Module:queue")
	q:push(root)
	while not(q:empty()) do
		local cur = q:front()
		q:pop()
		for i, t in pairs(cur.next or {}) do
			q:push(t)
		end
		if (cur ~= root) and (cur.father ~= root) then
			cur2 = cur.father
			while cur2.fail.next[cur.char] ~= nil and cur2 ~= root do
				cur2 = cur2.fail
			end
			cur.fail = cur2.fail.next[cur.char] or root
		else
			cur.fail = root
		end
	end
	return root
end

function string.replaceTrie(str, trie, extras)--用数据格式化文本
	local cur_state = trie
	local i = 1
	--local matched_times = 0
	while i <= mw.ustring.len(str) do
		local c = mw.ustring.sub(str, i, i)
		while cur_state.next[c] == nil and cur_state ~= trie do
			cur_state = cur_state.fail or trie
		end
		cur_state = cur_state.next[c] or trie
		if cur_state.item ~= nil then
			--matched_times = matched_times + 1matched_times, 
			local newStr = cur_state.item:callback(extras)
			-- mw.log(mw.ustring.sub(str, i - cur_state.len + 1, i)..' -> '..newStr)
			str = mw.ustring.sub(str, 1, i - cur_state.len)..newStr..mw.ustring.sub(str, i + 1, mw.ustring.len(str))
			i = i + mw.ustring.len(newStr) - cur_state.len
			cur_state = trie
		end
		i = i + 1
	end
	return str
end

function string.matchTrie(str, trie,text,extras)--用文本获取数据
	local cur_state = trie
	local index=1
	local i = 1
	--local matched_times = 0
	while i <= mw.ustring.len(str) do
		local c = mw.ustring.sub(str, i, i)
		while cur_state.next[c] == nil and cur_state ~= trie do
			cur_state = cur_state.fail or trie
		end
		cur_state = cur_state.next[c] or trie
		if cur_state.item ~= nil then
			--matched_times = matched_times + 1
			index = cur_state.item:matchback(extras,text,index)
			if index>#text then
				return index
			end
			-- mw.log(mw.ustring.sub(str, i - cur_state.len + 1, i)..' -> '..newStr)
			cur_state = trie
		end
		i = i + 1
	end
	return index
end
--时间单位。
--时间单位将指示时间段限定的范畴。
--时间单位皆有name,range属性,analysis、format函数

--时间单位需要能够从时间文本、时间段中提取值,也能赋值到这两者之中。
--时间单位有着占用组别,它们有着优先度,占用同一数值。如上旬与三月占用同一组。每一组只能有一个单位适用。
--解析器是固定的,但格式化是可变的。

local timeUnit={name="nil",_min=1,_max=math.huge,_priority=0,_begin=0}
--构建函数--
function timeUnit.base(tag,priority)--基础单位。
	local unit={
		tag=tag,
		_priority=priority,
	}
	return setmetatable(unit,timeUnit)
end
timeUnit.__index = timeUnit
function timeUnit:setName(text)--设置标签文本,仅用于调试
	self.name=text
	return self
end
function timeUnit:pattern(patternAnalysis,patternFormat)--设置模式字符串
	self.patternAnalysis=patternAnalysis or self.patternAnalysis
	self.patternFormat=patternFormat or self.patternFormat
	return self
end
function timeUnit:fill(number)--指示格式输出数字的必须位数
	self.patternFormat="%0"..number.."d"
	return self
end
function timeUnit:patternFixed(pattern)--纯粹形式
	self.patternAnalysis=pattern
	self.patternFormat=pattern
	return self
end
function timeUnit:patternPrefix(name)--前缀形式
	self.patternAnalysis=name.."^(%d+)"
	self.patternFormat=name.."%d"
	return self
end
function timeUnit:patternSuffix(name)--后缀形式
	self.patternAnalysis="^(%d+)"..name
	self.patternFormat="%d"..name
	return self
end--可以考虑中文数字支持
function timeUnit:priority(number)--设置优先度
	self._priority=number
	return self
end
function timeUnit:__lt(other)--排序使用
	return self._priority<other._priority
end
function timeUnit:b(number)--设置最小精度开始于,即对于区块开始于
	self._begin=number
	return self
end
function timeUnit:_convertTo(value)--到time时的值转换
	return value
end
function timeUnit:_convertFrom(value)--到字面时的值转换
	return value
end
function timeUnit:ratio(number)--设置倍率
	local convertTo=self._convertTo
	self._convertTo=function(value)
		return convertTo(value)*number
	end
	local convertFrom=self._convertFrom
	self._convertFrom=function(value)
		return convertFrom(value/number)
	end
	return self
end
function timeUnit:move(number)--设置值位移,即特殊情况下单位与实际值的差异(用于世纪)
	local convertTo=self._convertTo
	self._convertTo=function(value)
		return convertTo(value)+number
	end
	local convertFrom=self._convertFrom
	self._convertFrom=function(value)
		return convertFrom(value-number)
	end
	return self
end
function timeUnit:accuracy(min,max)--设置精度
	self._min=min
	self._max=max
	return self
end
function timeUnit:des(text)
	self.description=text
	return self
end
function timeUnit:formatFuc(fuc)--设置格式化函数
	self.formatText=fuc
	return self
end
function timeUnit:na()--指示不用于分析
	self._na=true
	return self
end
function timeUnit:f(pattern)--指示使用本unit格式化的指示符
	self.format=pattern
	return self
end
--延展构建--基于本单位的单位
function timeUnit:append()
	self.__index = self
	return setmetatable({},self)
end
function timeUnit:appendNumber(number)
	local unit=self:append()
	unit.patternAnalysis="^(%d+)"
	unit.patternFormat="%d"
	return unit
end
function timeUnit:appendPrefix(text)
	local unit=self:append()
	unit:patternPrefix(text)
	return unit
end
function timeUnit:appendSuffix(text)
	local unit=self:append()
	unit:patternSuffix(text)
	return unit
end
--功能函数
function timeUnit:available()--指示不用于分析
	return not self._na
end
function timeUnit:priorityCompare(other)--判断优先低于
	return self._priority<other._priority
end
function timeUnit:analysis(time,text,index)--从文字解析
	local value=text:match(self.patternAnalysis,index)
	if value then
	--assert(type(value)=="number",self.patternAnalysis..";"..text)
		_,index=text:find(self.patternAnalysis,index)--可以优化?
		index=index+1
		--time.units:push({self,value})
		return value,index
	end
	return nil,index
end
function timeUnit._convertTo(value)--到time时的值转换
	return value
end
function timeUnit._convertFrom(value)--到字面时的值转换
	return value
end
function timeUnit:supplyTime(time,value)--为time赋值
	time:setValue(self.tag,self._convertTo(value),self._min,self._max,self._begin)
end
function timeUnit:matchback(time,text,index) --分析用
	local value,index=self:analysis(time,text,index)
	if value then
		self:supplyTime(time,value)
	end
	return index
end
function timeUnit:getValue(time)--从time获取值
	local value=time:getValue(self.tag,self._min,self._max,self._begin,self._min)
	return value and self._convertFrom(value)
end
function timeUnit:formatText(value)--返回格式化文本
	return string.format(self.patternFormat,value)
end
function timeUnit:callback( time) --格式化用
	local value= self:getValue(time)
	if value then
		return self:formatText(value)
	end
	return ""
end

timeUnit.Multi={}--多标签识别
function timeUnit.Multi:analysis(time,text,index)--从文字解析
	local value={text:match(self.patternAnalysis,index)}
	if value[1] then
		_,index=text:find(self.patternAnalysis,index)--可以优化?
		--time.units:push({self,value})
		return value,index+1
	end
	return nil,index
end
function timeUnit.Multi:supplyTime(time,value)--为time赋值
	for index,unit in ipairs(self.units) do
		unit:supplyTime(time,value[index])
	end
end
function timeUnit.Multi:formatText(value)--返回格式化文本
	return string.format(self.patternFormat,unpack(value))
end
function timeUnit.Multi:getValue(time) 
	local t={}
	for index,unit in ipairs(self.units) do
		table.insert(t,unit:getValue(time))
	end
	return #t==#self.units and t
end
function timeUnit.multi(units)
	local unit=timeUnit.base()
	unit.units=units
	unit._priority=units[#units]._priority
	unit.analysis=timeUnit.Multi.analysis
	unit.supplyTime=timeUnit.Multi.supplyTime
	unit.formatText=timeUnit.Multi.formatText
	unit.getValue=timeUnit.Multi.getValue
	return unit
end
--[[--识别多个单位的连接
--这样就有点像语言识别系统了..说不定就该用语言识别系统做基础
function timeMultiUnit:analysis(time,text,index)
	local i=index
	local vt={}
	for _,unit in ipairs(self.units) do
		local value,i=unit:analysis(time,text,i)
		if not value then
			return nil,index
		end
		table.insert(vt,value)
	end
	return vt,i
end
function timeMultiUnit:supplyTime(time,value)--为time赋值
	for index,unit in ipairs(self.units) do
		unit:supplyTime(time,value[index])
	end
end
function timeMultiUnit:callBack(_, time) --格式化用
	local t={}
	for index,unit in ipairs(self.units) do
		table.insert(t,unit:callBack(_,time))
	end
	return table.concat(t)
end]]
timeUnit.List={}--文本列表单位,对应正当格式但不用阿拉伯数字描述的单位
function timeUnit.List:analysis(time,text,index)--从文字解析,匹配为time记录
	for value,name in pairs(self.names) do
		if text:sub(index,index+#name-1)==name then
			--mw.log(self.tag,value,index+#name,index)
			return value,index+#name
		end
	end
	return nil,index
end
function timeUnit.List:formatText(value)--返回格式化文本
	--mw.log(value,self.names[value])
	return self.names[value] or ""
end
function timeUnit:appendList(names)--扩展数组形式的单位表
	local unit=self:append()
	unit.names=names
	unit.analysis=timeUnit.List.analysis
	unit.formatText=timeUnit.List.formatText
	return unit
end

timeUnit.Group={}--文本列表单位,对应正当格式但不用阿拉伯数字描述的单位,并且允许使用不同的区间值
function timeUnit.Group.createIndex(t)  
	local a = {}
	for n in pairs(t) do
		a[#a+1] = n
	end
	table.sort(a)
	return a
end
timeUnit.Group.analysis=timeUnit.List.analysis
function timeUnit.Group:formatText(value)--返回格式化文本)
	for index,v in ipairs(self.index) do
		if v>value then
			if self.index[index-1] then
				return self.names[self.index[index-1]]
			else
				return ""
			end
		end
	end
	return self.names[self.index[#self.index]] or ""
end
function timeUnit:appendGroup(args)
	local unit=self:append()
	unit.names=args
	unit.index=timeUnit.Group.createIndex(args)
	unit.analysis=timeUnit.Group.analysis
	unit.formatText=timeUnit.Group.formatText
	return unit
end



--时间精度
--精度有两方面,未知的前缀与未知的后缀。
local timeAccuracy={
	max=1,--最前精度
	maxA=1,
	min=7,--最后精度
	minA=math.huge,
}
timeAccuracy.baseData={["year"]=7,["month"]=6,["week"]=5,["yday"]=4,["day"]=4,["wday"]=4,["hour"]=3,["min"]=2,["sec"]=1}
timeAccuracy.indexToTag={"sec","min","hour","day","week","month","year"}
function timeAccuracy.create(args)
	return setmetatable(args or {},timeAccuracy)
end
timeAccuracy.__index=timeAccuracy
timeAccuracy.clear=timeAccuracy.create{max=1,maxA=math.huge,min=7,minA=1}
function timeAccuracy.lt(l,la,r,ra)--小于
	return l<r or (l==r and la<ra)
end
function timeAccuracy.le(l,la,r,ra)--小于等于
	return l<r or (l==r and la<=ra)
end
function timeAccuracy:setMin(min,minA)
	self.min=min
	self.minA=minA
end
function timeAccuracy:setMax(max,maxA)
	self.max=max
	self.maxA=maxA
end
function timeAccuracy:isNull()
	return timeAccuracy.le(self.max,self.maxA,self.min,self.minA)
end
function timeAccuracy:limit(tag,min,max)--限制、精确范围
	local index=timeAccuracy.baseData[tag]
	max=max or min
	if timeAccuracy.lt(self.max,self.maxA,index,max) then
		self:setMax(index,max)
	end
	if timeAccuracy.lt(index,min,self.min,self.minA) then
		self:setMin(index,min)
	end--两者间的空间为已知精确
end
function timeAccuracy:_cover(index,value,direct)--遮盖、模糊范围
	if direct then--true为遮蔽右侧
		if timeAccuracy.lt(self.min,self.minA,index,value) then
			if value==math.huge then--进位
				self:setMin(index+1,1)
			else
				self:setMin(index,value)
			end
		end
	else
		if timeAccuracy.lt(index,value,self.max,self.maxA) then
			if value==1 then--进位
				self:setMax(index-1,math.huge)
			else
				self:setMax(index,value)
			end
		end
	end
end
function timeAccuracy:cover(tag,value,direct)--遮盖、模糊范围
	local index=timeAccuracy.baseData[tag]
	self:_cover(index,value,direct)
end
function timeAccuracy:coverBy(other,direct)--遮盖、模糊范围
	if direct then--true为遮蔽右侧
		self:_cover(other.max,other.maxA,direct)
	else
		self:_cover(other.min,other.minA,direct)
	end
end
function timeAccuracy:loverThan(tag,min,max)--是否比指定标签下的精度更低--即数据是否没有涵盖该精度
	local index=timeAccuracy.baseData[tag]
	max=max or min
	return timeAccuracy.lt(self.max,self.maxA,index,max) or timeAccuracy.lt(index,min,self.min,self.minA)
end

function timeAccuracy:getTagAccuracy(tag)--获取tag下精度,两个数。必须是范围包含的标签
	local index=timeAccuracy.baseData[tag]
	if self.max<index or index<self.min then
		return 
	end
	local first=self.max==index and self.maxA or math.huge
	local last=self.min==index and self.minA or 1
	return first,last
end
function timeAccuracy:contains(tag,accuracy)--包含精度
	return not self:loverThan(tag,accuracy)
end
function timeAccuracy:getMax()--获取最前精度
	return timeAccuracy.indexToTag[self.max],self.maxA
end
function timeAccuracy:getMin()--获取最后精度
	return timeAccuracy.indexToTag[self.min],self.minA,self.begin
end

function timeAccuracy.getTags_step(self,index)
	index=index-1
	if (index<self.min) then--超过界限
		return
	end
	if index==self.min then
		local min=self.minA
	end
	if index==self.max then
		local max=self.maxA
	end
	return index,timeAccuracy.indexToTag[index],min or 1,max or math.huge
end
function timeAccuracy:getTags()--遍历标签精度,从大到小
	return timeAccuracy.getTags_step,self,self.max+1
end

function timeAccuracy.getSupplyPreTags_step(tab,index)
	index=index+1
	if index>tab[2].max then--超过界限
		return
	end
	if index==tab[2].max then
		if index==tab[1].max and tab[1].maxA>=tab[2].maxA then
			return
		end
		return index,timeAccuracy.indexToTag[index],tab[2].maxA
	end
	return index,timeAccuracy.indexToTag[index],math.huge
end
function timeAccuracy:getSupplyPre(other)--获取other的更高精度的标签、精度 迭代器
	return timeAccuracy.getSupplyPreTags_step,{self,other},math.max(self.max,other.min)-1
end
function timeAccuracy.getSupplyAfterTags_step(tab,index)
	index=index-1
	if (index<tab[2].min) then--超过界限
		return
	end
	if index==tab[2].min then
		if index==tab[1].min and tab[1].minA<=tab[2].minA then
			return
		end
		return index,timeAccuracy.indexToTag[index],tab[2].minA
	end
	return index,timeAccuracy.indexToTag[index],1
end
function timeAccuracy:getSupplyAfter(other)--获取other的更高精度的标签、精度 迭代器
	return timeAccuracy.getSupplyAfterTags_step,{self,other},math.min(self.min,other.max)+1
end

--time 时间类
local time={year=1,month=1,week=1,day=1,wday=1,hour=0,min=0,sec=0}
time.zero=os.time(time)
function time.create(args)--设置值
	args=args or {}
	args.accuracy=timeAccuracy.create()
	return setmetatable(args,time)
end
time.__index=time
function time:setEnd(time)--结束时间点
	time:supply(self,true,false)
	time.accuracy=self.accuracy
	self._end=time
end
function time:getAccuracyEnd()--模糊度的范围结束时间点
	local tag,range=self.accuracy:getMin()
	--mw.log(tag,range)
	local e=mw.clone(self)
	e[tag]=e[tag]+range
	e:update()
	return e
end
function time:getEnd()--结束范围并结束模糊度的范围时间点
	if not self._accuracy_end then
		self._accuracy_end=(self._end or self):getAccuracyEnd()
	end
	return self._accuracy_end
end
function time.initializeUnit(lang_from,lang_to,connect)--初始化
	local base={--单位有优先度--占用同一标签的单位按照优先度予以保留--优先度从低到高都可运算ymd,新的ymd覆盖旧的。
	--进行time创建时将优先度从高到低依次调用构建,单位的会因精确已达到而跳过赋值
		century	=timeUnit.base("year",0)	:accuracy(100,math.huge)			:b(0):ratio(100):move(-199),
		years	=timeUnit.base("year",1)	:accuracy(10,math.huge)				:b(0),
		year	=timeUnit.base("year",2)	:accuracy(1,math.huge)				:b(1),
		month	=timeUnit.base("month",3)	:accuracy(1,math.huge)				:b(1),
		week	=timeUnit.base("week",4)	:accuracy(1,math.huge)				:b(1),
		wday	=timeUnit.base("wday",5)	:accuracy(1,math.huge)				:b(1),
		yday	=timeUnit.base("yday",5.5)	:accuracy(1,math.huge):na()			:b(1),
		day		=timeUnit.base("day",6)		:accuracy(1,math.huge)				:b(1),
		mer		=timeUnit.base("hour",7)	:accuracy(12,math.huge)				:b(0):ratio(12),
		hour	=timeUnit.base("hour",8)	:accuracy(1,math.huge)				:b(0),
		min		=timeUnit.base("min",9)		:accuracy(1,math.huge)				:b(0),
		sec		=timeUnit.base("sec",10)	:accuracy(1,math.huge)				:b(0),
		--timezone=timeUnit.base("timezone",11),--暂时无意义
	}
	local standard={--数字-符号格式。应最后分析。
		--数字识别。4位将识别为年,3位为日
		timeUnit	.multi{base.year,base.month,base.day}--ymd
					:pattern("^(%d+)\-(%d+)\-(%d+)","%04d\-%02d\-%02d")--正规模式
					:des("日期-年月日 (ISO 8601格式)(不支持省略)")
					:f("%E"),
		timeUnit	.multi{base.year,base.month,base.day}--ymd
					:pattern("^(%d+)%.(%d+)%.(%d+)","%04d\.%02d\.%02d")--泛用模式
					:des("日期-年月日 (ISO 8601格式)(不支持省略)")
					:f("%(Eo)"),
		timeUnit	.multi{base.year,base.month}--ym
					:pattern("^(%d%d%d%d+)\-(%d+)"),
		timeUnit	.multi{base.month,base.day}--md
					:pattern("^(%d%d-)\-(%d+)"),
		timeUnit	.multi{base.year,base.month,base.day}--ymd2
					:pattern("^(%d%d%d%d)\-?(%d%d)\-?(%d%d)"),--数字模式
							
		timeUnit	.multi{base.year,base.week,base.wday}--ywd
					:pattern("^(%d+)\-W(%d+)\-(%d+)","%04d\-W%02d\-%d")--正规模式
					:des("日期-年周星期 (ISO 8601格式)(不支持省略)")
					:f("%(Ew)"),
		timeUnit	.multi{base.year,base.week}--yw
					:pattern("^(%d%d%d%d+)\-?W(%d%d-)"),
		timeUnit	.multi{base.week,base.wday}--wd
					:pattern("^W(%d%d-)\-?(%d)"),
		timeUnit	.multi{base.year,base.week,base.wday}--ywd2
					:pattern("^(%d%d%d%d)\-?W(%d%d)\-?(%d)"),--数字模式

		timeUnit	.multi{base.hour,base.min,base.sec}--his
					:pattern("^(%d+)\:(%d+)\:(%d+)","%02d\:%02d\:%02d")--正规模式
					:des("时间-时分秒 (ISO 8601格式)(不支持省略)")
					:f("%e"),
		timeUnit	.multi{base.hour,base.min}:setName("--hi")
					:pattern("^(%d+)\:(%d+)"),--可能需要扩展
		timeUnit	.multi{base.hour,base.min,base.sec}--his2
					:pattern("^T(%d%d)\:?(%d%d)\:?(%d%d)"),
		base.year	:appendNumber()--四位纯数字--yearF
					:pattern("^(%d%d%d%d)"),

		base.mer	:appendList{[0]="am","pm"}--mer
					:des("根据时间是上午还是下午,输出am或pm")
					:f("%a"),
		base.mer	:appendList{[0]="AM","PM"}--meridiem
					:des("根据时间是上午还是下午,输出AM或PM")
					:f("%(au)"),
		timeUnit	.multi{base.hour,base.min}--timezone
					:priority(11)
					:pattern("^([-%+]%d+):?(%d+)")
					:des("时区"),--:f("%(au)")
							
	}
	local expend={--只用于格式化
		base.century:appendNumber()--centuryF
					:pattern("^(%d%d)")
					:des("日期-世纪,2位数字,补足前导0")
					:fill(2)
					:f("%(cf)"),
		base.years	:appendNumber()--yearsF
					:pattern("^(%d%d)")
					:des("日期-年代,2位数字,补足前导0")
					:fill(2)
					:accuracy(10,100)
					:f("%(tf)"),
		base.year	:appendNumber()--四位纯数字--yearF
					:pattern("^(%d%d%d%d)")
					:fill(4)
					:des("日期-年份,4位数字,补足前导0")
					:f("%(yf)"),
		base.month	:appendNumber()--monthF
					:pattern("^(%d%d)")
					:des("日期-月,2位数字,补足前导0")
					:fill(2)
					:f("%(mf)"),
		base.day	:appendNumber()--dayF
					:pattern("^(%d%d)")
					:des("日期-日,2位数字,补足前导0")
					:fill(2)
					:f("%(df)"),
		base.week	:appendNumber()--获得的W开头两位数字识别为周--weekF
					:pattern("^W(%d%d)")
					:des("日期-年内第几周,2位数字,补足前导0")
					:fill(2)
					:f("%(wf)"),
		base.hour	:appendNumber()--hourF
					:pattern("^(%d%d)")
					:des("时间-小时,2位数字,补足前导0")
					:fill(2)
					:f("%(hf)"),
		base.min	:appendNumber()--minF
					:pattern("^(%d%d)")
					:des("时间-分钟,2位数字,补足前导0")
					:fill(2)
					:f("%(if)"),
		base.sec	:appendNumber()--secF
					:pattern("^(%d%d)")
					:des("时间-秒,2位数字,补足前导0")
					:fill(2)
					:f("%(sf)"),
		base.century:appendNumber()--century
					:des("日期-世纪")
					:f("%c"),
		base.years	:appendNumber()--years
					:des("日期-年代")
					:f("%t"),
		base.year	:appendNumber()--year
					:des("日期-年份")
					:f("%y"),
		base.month	:appendNumber()--month
					:des("日期-月")
					:f("%m"),
		base.week	:appendNumber()--week
					:des("日期-年内第几周")
					:f("%w"),
		base.day	:appendNumber()--day	
					:des("日期-日")
					:f("%d"),
		base.yday	:appendNumber()--yday
					:des("日期-日 年内第几日")
					:f("%(dy)"),
		base.wday	:appendNumber()--已有周,获得的一位数字识别为星期--wday
					:pattern("^(%d)")
					:des("日期-星期,1位数字")
					:f("%l"),
		base.hour	:appendNumber()--hour
					:des("时间-小时")
					:f("%h"),
		base.hour	:appendNumber()--hour
					:des("时间-小时 十二小时制")
					:accuracy(1,12)
					:b(0)
					:f("%(hy)"),
		base.min	:appendNumber()--min	
					:des("时间-分钟")
					:f("%i"),
		base.sec	:appendNumber()--sec	
					:des("时间-秒")
					:f("%s"),
		timeUnit	.multi{base.year,base.month,base.day,base.hour,base.min,base.sec}--ios	
					:pattern("^%d%d%d%d-?%d%d-%d%d T%%d%d:?%d%d:?%d%d","%04d-%02d-%02d T%02d:%02d:%02d")
					:des("年月日时分秒 (ISO 8601格式)(不支持省略)")
					:f("%X"),
		timeUnit	.multi{base.year,base.week,base.day,base.hour,base.min,base.sec}--ios2
					:pattern("%d%d%d%d-?W%d%d-?%d%d T%%d%d:?%d%d:?%d%d","%04dW%02d-%d T%02d:%02d:%02d")
					:des("年周日时分秒 (ISO 8601格式)(不支持省略)")
					:f("%x"),
	}
	local lang={}
	lang.en={--英语格式
		base.years	:appendSuffix("s")--years	
					:accuracy(10,math.huge)
					:f("%T"),
		base.month	:appendList{"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}--monthShort
					:f("%(Ms)"),
		base.month	:appendList{"January","February","March","April","May","June","July","August","September","October","November","December"}
					:f("%M"),--month		=
		base.wday	:appendList{"Mon","Tue","Wed","Thu","Fri","Sat","Sun"}--wdayShort
					:f("%(Ls)"),
		base.wday	:appendList{"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"}--wday	
					:f("%L"),
		base.day	:appendSuffix("nd")--day		
					:formatFuc(
						function(self,value)
							return value==1 and value.."st" or value.."nd"
						end)
					:f("%D"),
		base.day	:appendSuffix("st"),--day2
	}
	
	lang.zh={--中文格式
		base.century:appendSuffix("世纪")--century
					:des("日期-世纪 单位“世纪”")
					:f("%C"),
		base.years	:appendSuffix("年代")--yearsF
					:pattern("^%d%d年代")
					:des("日期-年代 单位“年代”,只取后两位")
					:accuracy(10,100)
					:f("%(Tf)"),
		base.years	:appendSuffix("年代")--years
					:des("日期-年代 单位“年代”")
					:accuracy(10,math.huge)
					:f("%T"),
		base.year	:appendSuffix("年")--year
					:des("日期-年 单位“年”")
					:f("%Y"),
		base.month	:appendSuffix("月")--month
					:des("日期-月 单位“月”")
					:f("%M"),
		base.month	:appendList{"一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"}
					:des("日期-月 中文文字")--monthC	
					:f("%(Mc)"),
		base.week	:appendSuffix("周")--weekN	=
					:pattern("^第d%+周","第d%周"),
		base.week	:appendSuffix("周")--week
					:des("日期-周 单位“周”")
					:f("%W"),
		base.day	:appendSuffix("日")--day	
					:des("日期-日 单位“日”")
					:f("%D"),
		base.yday	:appendSuffix("日")--yday	
					:des("日期-日 年内第几日 单位“日”")
					:na()
					:f("%(Dy)"),
		base.day	:appendSuffix("号")--dayO
					:des("日期-日 单位“号”")
					:f("%(Do)"),
		base.wday	:appendList{"星期一","星期二","星期三","星期四","星期五","星期六","星期日"}--wday	
					:des("日期-星期 中文文字“星期”")
					:f("%L"),
		base.wday	:appendList{"周一","周二","周三","周四","周五","周六","周日"}--wdaySS	
					:des("日期-星期 中文文字大写“周”")
					:f("%(Lss)"),
		base.wday	:appendList{"一","二","三","四","五","六","日"}--wdayS	
					:des("日期-星期 只输出一个中文文字")
					:f("%(Ls)"),
		base.hour	:appendSuffix("时")--hour
					:des("时间-时 单位“时”")
					:f("%H"),
		base.hour	:appendSuffix("时")--hour
					:des("时间-时 单位“时” 十二小时制") 
					:accuracy(1,12)
					:na()
					:f("%(Hy)"),
		base.hour	:appendSuffix("点")--hourO	
					:des("时间-时 单位“点”")
					:f("%(Ho)"),
		base.min	:appendSuffix("分")--min	
					:des("时间-分 单位“分”")
					:f("%I"),
		base.sec	:appendSuffix("秒")--sec	
					:des("时间-秒 单位“秒”")
					:f("%S"),
		--wday	=base.week		:appendSuffix("星期","^星期d%+","星期d%"),
		
		--shortMonth	=base.month:appendList("一","二","三","四","五","六","七","八","九","十","十一","十二"),
		base.day	:appendGroup{
			[1]="上旬",[11]="中旬",[21]="下旬"
		}			:priority(3.5)--tendays	
					:accuracy(10,math.huge)
					:b(1)
					:des("日期-月内描述“旬”,十日为一旬")
					:f("%(Mi)"),
		base.mer	:appendList{[0]="上午","下午"}--mer		
					:des("时间-根据时间输出上午或下午")
					:f("%A"),
		base.hour	:appendGroup{
			[0]="凌晨",[7]="上午",[11]="中午",[13]="下午",[17]="傍晚",[19]="晚上",[22]="深夜"--有争议
		}			:priority(7.5)--inday		=
					:des("时间-日内详细描述")
					:f("%(Di)"),
	}
	local filter=function(tab)
		local t={}
		for _,unit in ipairs(tab) do
			if unit:available() then
				table.insert(t,unit)
			end
		end
		return t
	end
	time.analysisTable={}--分析表--本来是可以写成语言,树状分析,但是暂且看来并没有必要。为了兼容更多模糊写法。
	if lang_from=="all" then
		for _,l in pairs(lang) do
			table.insert(time.analysisTable,filter(l))
		end
	else--lang=="zh"
		table.insert(time.analysisTable,filter(lang[lang_from or "zh"]))
	end
	table.insert(time.analysisTable,filter(standard))

	time.analysisConnect={--时间连接符,间隔两时间点
		"^到","^至","^\-","^\b","^\\","^、"
	}
	time.analysisIgnore={--忽略符、间隔符。
		"^%s","^ ","^,","^—"
	}

	time.formatTable={lang[lang_to or "zh"],expend,standard}--格式化表
	
	if connect then
		time.formatConnect=connect
	else
		if lang_to=="en" then
			time.formatConnect="-"
		else
			time.formatConnect="到"
		end
	end
	--追加词,暂未实现--追加在单位后的后缀,可以不断追加。后缀与原单位相关。
	local about={
		--about		=base.hour	:appendFixed("左右"),
		--about2		=base.hour	:appendFixed("前后"),
		--about2		=base.hour	:appendFixed("约"),
		--about2		=base.hour	:appendFixed("大概"),
		--about2		=base.hour	:appendFixed("之间"),
		--about2		=base.hour	:appendFixed("开始"),
		--about2		=base.hour	:appendFixed("附近"),
	}
	time.formatTrie = string.buildTrie(time.formatTable)
	return standard,expend,lang
end

--功能函数
function time:isEmpty()--是否为空
	return self.accuracy:isNull()
end
function time:_setValue(tag,value,min,max,begin)
	--mw.log("set",tag,value,min,max,begin,self:_getValue(tag))
	local f,l=self.accuracy:getTagAccuracy(tag)
	value=value-begin
	--value=math.mod(value,max)-math.mod(value,min)
	value=value-math.mod(value,min)
	if f then
		local valueTag=self[tag]-begin
		value=value-math.mod(value,f)+math.mod(value,l)+math.mod(valueTag,f)-math.mod(valueTag,l)--保留值-保留信息已有精度部分内容
		--mw.log(tag,min,max,begin,value,value,math.mod(value,f),math.mod(value,l),math.mod(valueTag,f),math.mod(valueTag,l))
	end
	value=value+begin
	self[tag]=value--+math.mod(begin,min)
	--mw.log("set","result",tag,self[tag])
end
function time:forceSetValue(tag,value,min,max,begin)--强制设置值--内部函数
	self:_setValue(tag,value,min,max,begin)
	self.accuracy:limit(tag,min,max)
end
function time:setValue(tag,value,min,max,begin)--设置值--内部函数
	if self.accuracy:loverThan(tag,min,max) then
		self:forceSetValue(tag,value,min,max,begin or 0)
	end
end

function time:_getValue(tag)--实际记录值
	local f,l=self.accuracy:getTagAccuracy(tag)
	if f then
		return self[tag]
	end
	return time[tag]
end
function time:forceGetValue(tag,min,max,begin)--强制获取值
	local value=self[tag]-begin
	local f,l=self.accuracy:getTagAccuracy(tag)
	if f then
		max=math.min(f,max)
		min=math.max(l,min)
	end
	--mw.log("-->",tag,self[tag],max,min,math.mod(value,max)-math.mod(value,min))
	return math.mod(value,max)-math.mod(value,min)+begin--+self.accuracy:getTagBegin(tag)
end
function time:getValue(tag,min,max,begin)--获取值
	min=min or 1
	max=max or math.huge
	if self.accuracy:contains(tag,min,max) then
		return self:forceGetValue(tag,min,max,begin)
	end
end
function time:getValueIgnore(tag,min,max,begin)--获取值--忽略粗略精度版本
	min=min or 1
	max=max or math.huge
	local f,l=self.accuracy:getTagAccuracy(tag)
	if f~=max or l~=min then
		return nil
	end
	return self:forceGetValue(tag,min,max,begin)
end
function time:update()--指示需要更新
	self.value=nil
	self._accuracy_end=nil
	self._sorted=false
end
function time:_getNumber()
	if not self.value then--改动后清空
		local t={}
		for _,tag in ipairs(time.keyData) do
			t[tag]=self:_getValue(tag) or time[tag]
		end
		if not rawget(self,"month") and not rawget(self,"day") then--处理周问题
			local week=self:_getValue("week")
			if week then
				local wday=os.date("*t",os.time({year=self.year,month=1,day=1})).wday-1--年内第一天的星期 减去1是因为lua标准中1代表星期日
				if wday==0 then wday=7 end--ios标准
				t.day= week*7+(wday>4 and 0 or -7)+self.wday-wday+1
			end
		end
		self.value=os.time(t)
	end
	return self.value
end
function time:getNumber()--获取计算值
	return self:_getNumber(),self:getEnd():_getNumber()
end
time.compare={--时间比较结果常数
	before=1,--完全在之前
	equal=2,--相同
	after=3,--完全在之后
	include=4,--包含
	inside=5,--被包含
	conflict=6,--冲突
}
time.compare=setmetatable(time.compare,{--时间比较,理论上只允许发生在同精确度的时间上。
	__call=function(self,time1,time2)
		local b1,e1=time1:getNumber()
		local b2,e2=time2:getNumber()
		--mw.log(tostring(time1),tostring(time2))
		--mw.log(b1,e1,b2,e2)
		if e1<=b2 then return self.before end
		if e2<=b1 then return self.after end
		if b1==b2 and e1==e2 then return self.equal end
		if b1<=b2 then
			if e2<=e1 then return self.include end
		end
		if b2<=b1 then
			if e1<=e2 then return self.inside end
		end
		return self.conflict
	end
})
function time:__eq(other)
	return self:compare(other)==time.compare.equal
end
function time:__lt(other)
	return self:compare(other)==time.compare.before
end
time.keyData={"year","month","day","hour","min","sec"}
time.baseData={"year","month","week","wday","yday","day","wday","hour","min","sec"}
function time:supply(other,pre,after)--利用另一个时间对此时间精确度补足
	pre=pre==nil and true or pre
	after=after==nil and true or after
	if pre then
		for _,tag,accuracy in self.accuracy:getSupplyPre(other.accuracy) do
			self:_setValue(tag,other:_getValue(tag),1,accuracy,0)
		end
		if self._end then
			for _,tag,accuracy in self.accuracy:getSupplyPre(other.accuracy) do
				self._end:_setValue(tag,other:_getValue(tag),1,accuracy,0)
			end
		end
		self.accuracy:limit(other.accuracy:getMax())
	end
	if after then
		for _,tag,accuracy in self.accuracy:getSupplyAfter(other.accuracy) do
			self:_setValue(tag,other:_getValue(tag),accuracy,math.huge,0)
		end
		if self._end then
			for _,tag,accuracy in self.accuracy:getSupplyAfter(other.accuracy) do
				self._end:_setValue(tag,other:_getValue(tag),accuracy,math.huge,0)
			end
		end
		local tag,min=other.accuracy:getMin()
		self.accuracy:limit(tag,min,min)
	end
	self:update()
	return self
end
function time:cover(other,direct)--利用另一个时间对此时间精确度减损遮盖
	--direct指示遮蔽方向,true遮蔽后部精度,false遮蔽前部精度
	self.accuracy:coverBy(other.accuracy,direct)
	self:update()
	return self
end
function time:coverRange(other)--遮盖other中到_end前后一致部分单位
	local tag,min
	for _,t,i in other.accuracy:getTags() do
		if other._end and other._end[t]~=other[t] then
			break
		end
		tag=t
		min=i
	end
	if tag then
		self.accuracy:cover(tag,min,false)
	else
		tag,min=other.accuracy:getMax()
		self.accuracy:cover(tag,min,false)
	end
	--mw.log("tag",tag,min)
	self:update()
	return self
end
function time:coverUnit(unitTag,direct)--利用unit格式索引unit并以此进行遮盖 也可以认为是截取信息,截取从unit开始的信息--种种问题暂且只支持主要单位
	local unit
	for _,group in ipairs(self.formatTable) do
		for _,u in ipairs(group) do
			if u.format==unitTag then
				unit=u
				break
			end
		end
	end
	if unit then
		--mw.log(self.accuracy.min,self.accuracy.minA,self.accuracy.max,self.accuracy.maxA)
		self.accuracy:cover(unit.tag,direct and unit._min or unit._max,direct)--有点不规范
		--mw.log(self.accuracy.min,self.accuracy.minA,self.accuracy.max,self.accuracy.maxA)
		self:update()
	end
	return self
end
function time:_add(tag,value)
	t[tag]=t[tag]+value
	if self._end then
		self._end[tag]=self._end[tag]+value
	end
end
function time:add(tag,value)--时间位移--暂且只有在具有该精确值时才生效
	self._add(tag,value)
	self:update()
end
function time:getMin()--获取最小精确标签
	return self.accuracy:getMin()
end
function time:forceAccuracy()--强制模糊度
	self.accuracy=timeAccuracy.clear
end
function time:__connect(other)--连接时间,取前者到后者产生区间。模糊处使用前者补足后者--关于模糊前
	local b=mw.clone(self)
	local e=mw.clone(other)
	b:setEnd(e)
	b:update()
	return b
end
function time:__add(other)
	local b=mw.clone(self)
	for _,tag in ipairs(time.baseData) do
		local value=other:getValue(tag)
		if value then
			local v=self:getValue(tag)
			b:_add(tag,v)
		end
	end
	b:update()
	return b
end
function time:__sub(other)
	local b=mw.clone(self)
	for _,tag in ipairs(time.baseData) do
		local value=other:getValue(tag)
		if value then
			local v=self:getValue(tag)
			b:_add(tag,-v)
		end
	end
	b:update()
	return b
end
function time.currentTimeZone()
	if not time._currentTimeZone then
		local a = os.date('!*t',os.time())--中时区的时间
		local b = os.date('*t',os.time())
		time._currentTimeZone= os.difftime(os.time(b), os.time(a))
	end
	return time._currentTimeZone
end
function time.normalizeZone(timezone)
	if timezone == nil or #timezone == 0 then
		return currentTimeZone() --用户当前时区
	else
		local hour, min = mw.ustring.match(mw.text.trim(timezone), "^([-%+]?%d+):?(%d*)$")
		if hour == nil then
			error("时区参数格式不正确。")
		end
		return (tonumber(hour)*60+tonumber(min))*60
	end
end
function time:convert(o_timezone,c_timezone)--改变时区
	local ot=time.normalizeZone(o_timezone)
	local ct=time.normalizeZone(c_timezone or mw.getCurrentFrame():callParserFunction( "#var","timezone"))
	self:add("sec",ct-ot)
end
function time:setData(t)--设置数据
	for _,tag in ipairs(time.baseData) do
		self[tag]=t[tag]
	end
end
function time:sort()--规范数据
	if self._sorted then
		return self
	end
	self.value=self:_getNumber()
	local t=os.date("*t",self.value)
	t.wday=t.wday-1
	if t.wday==0 then t.wday=7 end--ios标准
	self:setData(t)
	local wday=math.mod(self.wday-self.yday,7)
	wday=wday>0 and wday or 7+wday--不包括0
	self.week=math.floor((self.yday+1-self.wday)/7)+(wday>4 and -1 or 0)+2
	if self._end then
		self._end:sort()
	end
	self._sorted=true
	return self
end
--文本转换
function time.sortUnits(uv1,uv2)
	return uv1.unit:priorityCompare(uv2.unit)
end
function time.analysis_step(text,index)
	local value
	for n1,group in ipairs(time.analysisTable) do
		for n2,unit in ipairs(group) do
			--mw.log("name",n1,n2,text:sub(index),unit.patternAnalysis)
			value,index=unit:analysis(time,text,index)
			if value then--!需要追加模糊词的处理
				--mw.log("analysis!")
				return unit,value,index
			end
		end
	end
	return nil,nil,index
end
function time.analysisSp(analysis_pattern)
	local value
	local trie=time.formatTrie
	local function fuc(text,index)
		local time1=time.create()
		local ni=string.matchTrie(analysis_pattern,trie,text:sub(index),time1)
		return time1,index+ni-1
	end
	return fuc
end
function time.analysis_simple(text,index)--处理不含连接符的时间文本
	local unitvalue={}
	
	local unit,value
	repeat
		repeat--trim
			local b,e=string.findAny(text,time.analysisIgnore,index)--连接符处理,可能需要多段支持
			if b then
				index=e+1
			end
		until(not b)
		--mw.log("analysis!",text:sub(index))
		
		unit,value,index= time.analysis_step(text,index)
		if unit then
			table.insert(unitvalue,{unit=unit,value=value})
		end
	until(unit==nil or index>#text)
	table.sort(unitvalue,time.sortUnits)--必须保证信息是连成段的,不允许空隙
	local time1=time.create()
	for _,uv in ipairs(unitvalue) do
		uv.unit:supplyTime(time1,uv.value)
	end
	return time1,index
end
function time.analysis(text,analysis_pattern)--分析文本
	local analysis=analysis_pattern and time.analysisSp(analysis_pattern) or time.analysis_simple
	local time1,index=analysis(text,1,analysis_pattern)
	local time2
	repeat 
		local b,e=string.findAny(text,time.analysisConnect,index)--连接符处理,可能需要多段支持
		if b then
			time2,index=analysis(text,e+1,analysis_pattern)
		end
	until(not b)
	if time2 then
		--error(table.concat({time2.year,time2.month,time2.day},";"))
		time1:setEnd(time2)
		--error(table.concat({time1._end.year,time1._end.month,time1._end.day},";"))
	end
	return time1,index
end
function time:format(pattern,ignore)--格式化--使用匹配符,指示忽略粗略描述
	self:sort()
	if self._end then
		self._end:sort()
	end
	local getvalue,accuracy
	if ignore then
		getvalue=time.getValue
		time.getValue=time.getValueIgnore
	elseif ignore==false then
		getvalue=time.getValue
		time.getValue=time.forceGetValue
	end
	local text=string.replaceTrie(pattern,time.formatTrie,self)
	if self._end then
		if self._end:_getNumber()~=self:_getNumber() then
			text=text..self.formatConnect..string.replaceTrie(pattern,time.formatTrie,self._end)
		end
	end
	if getvalue then
		time.getValue=getvalue
	end
	return text--range问题
end
function time:__tostring()
	return self:format("%Y%M%D%H%I%S")
end
--主函数
module.time=time--用于继承等
function module.formatList(frame)--参数表
	local standard,expend,lang=module.initialize()
    local var_array = require("Module:Var-array")
    local formatNames = {}
	local formatList = {}
	table.insert(formatNames,"")
	local list = {}
    for _, unit in pairs(standard) do
    	if unit.format then
        	table.insert(list, { unit.format, unit.description })
        end
    end
    for _, unit in pairs(expend) do
    	if unit.format then
        	table.insert(list, { unit.format, unit.description })
        end
    end
	table.insert(formatList,list)
    for name, l in pairs(lang) do
		table.insert(formatNames, name)
		local list = {}
		for _, unit in pairs(l) do
	    	if unit.format then
	        	table.insert(list, { unit.format, unit.description })
	        end
		end
		table.insert(formatList,list)
    end
	var_array.new("time.convert.formatlist.name", formatNames)
    var_array.new("time.convert.formatlist", formatList)
end
function module.toTime(text,analysis_pattern)--获取时间类
    return time.analysis(text or "",analysis_pattern)
end
function module.initialize(from,to,connect)--设置参数初始化
	return time.initializeUnit(from,to,connect)
end
function module.format(text,pattern,ignore,o_timezone,c_timezone,analysis_pattern)--格式化文本
	assert(text,"text cannot be nil")
	assert(pattern,"pattern cannot be nil")
	local time=time.analysis(text,analysis_pattern)
	if o_timezone then
		time=time:convert(o_timezone,c_timezone)
	end
    return time:format(pattern,ignore)
end

function module._main(args)--主函数
	module.initialize(args.from or args["原语言"],args.to or args["目标语言"],args.connect or args["连接符"])
	local text=args[1] or args.text or args["时间文本"]
	local pattern=args[2] or args.pattern or args["格式化字符串"]
	local ignore=args[3] or args.force or args["强制精确度"]
	if ignore=="true" then
		ignore=true
	elseif ignore=="false" then
		ignore=false
	else
		ignore=nil
	end
	local o_timezone=args[4] or args.o_timezone or args.o_tz or args["原时区"]
	local c_timezone=args.c_timezone or args.c_tz or args["现时区"]
	if not pattern then return "" end
	local analysis_pattern=args[5] or args.analysis_pattern or args.a_pattern or args["分析字符串"]
	return module.format(text,pattern,ignore,o_timezone,c_timezone,analysis_pattern)
end
function module.main(frame)--主函数
	local args = getArgs(frame)
	return module._main(args)
end
 
return module