require"Амодуль:No globals"localTime={}--[[Check if a value is a number in the given range@param mixed value@param number min@param number max@return boolean]]--localfunctionvalidateNumberInRange(value,min,max)returntype(value)=='number'andvalue>=minandvalue<=maxend--Internal functions--[[Validate a time defintion@param table definition data@return boolean]]--localfunctionvalidate(definition)--Validate constantesifnotTime.knowsPrecision(definition.precision)or(definition.calendar~=Time.CALENDAR.GREGORIANanddefinition.calendar~=Time.CALENDAR.JULIAN)thenreturnfalseend--Validate yearifnot(type(definition.year)=='number'or(definition.year==nilandprecision==Time.PRECISION.DAY))thenreturnfalseendifdefinition.precision<=Time.PRECISION.YEARthenreturntrueend--Validate monthifnotvalidateNumberInRange(definition.month,1,12)thenreturnfalseendifdefinition.precision<=Time.PRECISION.MONTHthenreturntrueend--Validate dayifnotvalidateNumberInRange(definition.day,1,31)thenreturnfalseendifdefinition.precision<=Time.PRECISION.DAYthenreturntrueend--Validate hourifnotvalidateNumberInRange(definition.hour,0,23)thenreturnfalseendifdefinition.precision<=Time.PRECISION.HOURthenreturntrueend--Validate minuteifnotvalidateNumberInRange(definition.minute,0,59)thenreturnfalseendifdefinition.precision<=Time.PRECISION.MINUTEthenreturntrueend--Validate secondifnotvalidateNumberInRange(definition.second,0,60)thenreturnfalseendreturntrueend--[[Try to find the relevant precision for a time definition@param table time definition@return number the precision]]--localfunctionguessPrecision(definition)ifdefinition.month==nilthenreturnTime.PRECISION.YEARelseifdefinition.day==nilthenreturnTime.PRECISION.MONTHelseifdefinition.hour==nilthenreturnTime.PRECISION.DAYelseifdefinition.minute==nilthenreturnTime.PRECISION.HOURelseifdefinition.second==nilthenreturnTime.PRECISION.MINUTEelsereturnTime.PRECISION.SECONDendend--[[Try to find the relevant calendar for a time definition@param table time definition@return string the calendar name]]--localfunctionguessCalendar(definition)ifdefinition.year~=nilanddefinition.year<1583anddefinition.precision>Time.PRECISION.MONTHthenreturnTime.CALENDAR.JULIANelsereturnTime.CALENDAR.GREGORIANendend--[[Parse an ISO 8601 string and return it as a time definition@param string iso the iso datetime@param boolean withoutRecurrence concider date in the format XX-XX as year-month and not month-day@return table]]--localfunctionparseIso8601(iso,withoutRecurrence)localdefinition={}--Split date and timeiso=mw.text.trim(iso:upper())localbeginMatch,endMatch,date,time,offset=iso:find('([%+%-]?[%d%-]+)[T ]?([%d%.:]*)([Z%+%-]?[%d:]*)')ifbeginMatch~=1orendMatch~=iso:len()then--iso is not a valid ISO stringreturn{}end--dateifdate~=nilthenlocalisBC=falseifdate:sub(1,1)=='-'thenisBC=truedate=date:sub(2,date:len())endlocalparts=mw.text.split(date,'-')ifnotwithoutRecurrenceandtable.maxn(parts)==2andparts[1]:len()==2then--MM-DD casedefinition.month=tonumber(parts[1])definition.day=tonumber(parts[2])elseifisBCthendefinition.year=-1*tonumber(parts[1])-1--Years BC are counted since 0 and not -1elsedefinition.year=tonumber(parts[1])enddefinition.month=tonumber(parts[2])definition.day=tonumber(parts[3])endend--timeiftime~=nilthenlocalparts=mw.text.split(time,':')definition.hour=tonumber(parts[1])definition.minute=tonumber(parts[2])definition.second=tonumber(parts[3])end--ofsetifoffset~=nilthenifoffset=='Z'thendefinition.utcoffset='+00:00'elsedefinition.utcoffset=offsetendendreturndefinitionend--[[Format UTC offset for ISO output@param string offset UTC offset@return string UTC offset for ISO]]--localfunctionformatUtcOffsetForIso(offset)ifoffset=='+00:00'thenreturn'Z'elsereturnoffsetendend--[[Prepend as mutch as needed the character c to the string str in order to to have a string of length length@param mixed str@param string c@param number length@return string]]--localfunctionprepend(str,c,length)str=tostring(str)whilestr:len()<lengthdostr=c..strendreturnstrendlocalfunctioneq(t1,t2)returnnot(t1<t2ort2<t1)endlocalfunctionlt(t1,t2)ift1.calendar~=t2.calendarthen-- ...endift1.year~=t2.yearthenreturnt1.year<t2.yearendift1.month~=t2.monththenreturnt1.month<t2.monthendreturnt1.day<t2.dayend--Public interface--[[Build a new Time@param table definition definition of the time@return Time|nil]]--functionTime.new(definition)--Default valuesifdefinition.precision==nilthendefinition.precision=guessPrecision(definition)endifdefinition.calendar==nilthendefinition.calendar=guessCalendar(definition)endifnotvalidate(definition)thenreturnnilendlocaltime={year=definition.yearornil,month=definition.monthor1,day=definition.dayor1,hour=definition.houror0,minute=definition.minuteor0,second=definition.secondor0,utcoffset=definition.utcoffsetor'+00:00',calendar=definition.calendarorTime.CALENDAR.GREGORIAN,precision=definition.precisionor0}setmetatable(time,{__index=Time,__lt=lt,__eq=eq,__tostring=function(self)returnself:toString()end})returntimeend--[[Build a new Time from an ISO 8601 datetime@param string iso the time as ISO string@param boolean withoutRecurrence concider date in the format XX-XX as year-month and not month-day@return Time|nil]]--functionTime.newFromIso8601(iso,withoutRecurrence)returnTime.new(parseIso8601(iso,withoutRecurrence))end--[[Build a new Time from a Wikidata time value@param table wikidataValue the time as represented by Wikidata@return Time|nil]]--functionTime.newFromWikidataValue(wikidataValue)localdefinition=parseIso8601(wikidataValue.time)definition.precision=wikidataValue.precisionifwikidataValue.calendarmodel=='http://www.wikidata.org/entity/Q1985727'thendefinition.calendar=Time.CALENDAR.GREGORIANelseifwikidataValue.calendarmodel=='http://www.wikidata.org/entity/Q1985786'thendefinition.calendar=Time.CALENDAR.JULIANelsereturnnilendreturnTime.new(definition)end--[[Return a Time as a ISO 8601 string@return string]]--functionTime:toIso8601()localiso=''ifself.year~=nilthenifself.year<0then--Years BC are counted since 0 and not -1iso='-'..prepend(-1*self.year-1,'0',4)elseiso=prepend(self.year,'0',4)endend--monthifself.precision<Time.PRECISION.MONTHthenreturnisoendifself.iso~=''theniso=iso..'-'endiso=iso..prepend(self.month,'0',2)--dayifself.precision<Time.PRECISION.DAYthenreturnisoendiso=iso..'-'..prepend(self.day,'0',2)--hourifself.precision<Time.PRECISION.HOURthenreturnisoendiso=iso..'T'..prepend(self.hour,'0',2)--minuteifself.precision<Time.PRECISION.MINUTEthenreturniso..formatUtcOffsetForIso(self.utcoffset)endiso=iso..':'..prepend(self.minute,'0',2)--secondifself.precision<Time.PRECISION.SECONDthenreturniso..formatUtcOffsetForIso(self.utcoffset)endreturniso..':'..prepend(self.second,'0',2)..formatUtcOffsetForIso(self.utcoffset)end--[[Return a Time as a string@param mw.language|string|nil language to use. By default the content language.@return string]]--functionTime:toString(language)iflanguage==nilthenlanguage=mw.language.getContentLanguage()elseiftype(language)=='string'thenlanguage=mw.language.new(language)end--return language:formatDate( 'r', self:toIso8601() )returnself:toIso8601()--TODO: improveend--[[Return a Time in HTMl (with a @param mw.language|string|nil language to use. By default the content language.@param table|nil attributes table of attributes to add to the @return string]]--functionTime:toHtml(language,attributes)ifattributes==nilthenattributes={}endattributes['datetime']=self:toIso8601()returnmw.text.tag('time',attributes,self:toString(language))end--[[All possible precisions for a Time (same ids as Wikibase)]]--Time.PRECISION={GY=0,--GigayearMY100=1,--100 MegayearsMY10=2,--10 MegayearsMY=3,--MegayearKY100=4,--100 KiloyearsKY10=5,--10 KiloyearsKY=6,--KiloyearYEAR100=7,--100 yearsYEAR10=8,--10 yearsYEAR=9,MONTH=10,DAY=11,HOUR=12,MINUTE=13,SECOND=14}--[[Check if the precision is known@param number precision ID@return boolean]]--functionTime.knowsPrecision(precision)for_,idinpairs(Time.PRECISION)doifid==precisionthenreturntrueendendreturnfalseend--[[Supported calendar models]]--Time.CALENDAR={GREGORIAN='Gregorian',JULIAN='Julian'}returnTime