Modul:Time

Time[mi ez?] • [dokumentáció: mutat, szerkeszt] • [tesztek: sikeres: 6, sikertelen: 0, kihagyva: 0 (részletek)]

Dátumok kezelése, egyelőre leginkább a Wikidatában tárolt dátumok megjelenítése, a Wikidata modulon keresztül.

Források

require('strict')local Time = {}--Internal functions--[[Check if a value is a number in the given range@param mixed value@param number min@param number max@return boolean]]--local function validateNumberInRange( value, min, max )return type( value ) == 'number' and value >= min and value <= maxend--[[Validate a time defintion@param table definition data@return boolean]]--local function validate(definition)--Validate constantsif not Time.knowsPrecision(definition.precision) or (definition.calendar ~= Time.CALENDAR.GREGORIAN and definition.calendar ~= Time.CALENDAR.JULIAN) thenreturn falseend--Validate yearif not (type( definition.year ) == 'number' or (definition.year == nil and precision == Time.PRECISION.DAY)) thenreturn falseendif definition.precision <= Time.PRECISION.YEAR thenreturn trueend--Validate monthif not validateNumberInRange( definition.month, 1, 12 ) thenreturn falseendif definition.precision <= Time.PRECISION.MONTH thenreturn trueend--Validate dayif not validateNumberInRange( definition.day, 1, 31 ) thenreturn falseendif definition.precision <= Time.PRECISION.DAY thenreturn trueend--Validate hourif not validateNumberInRange( definition.hour, 0, 23 ) thenreturn falseendif definition.precision <= Time.PRECISION.HOUR thenreturn trueend--Validate minuteif not validateNumberInRange( definition.minute, 0, 59 ) thenreturn falseendif definition.precision <= Time.PRECISION.MINUTE thenreturn trueend--Validate secondif not validateNumberInRange( definition.second, 0, 60 ) thenreturn falseendreturn trueend--[[Try to find the relevant precision for a time definition@param table time definition@return number the precision]]--local function guessPrecision(definition)if definition.month == nil or (definition.month == 0 and definition.day == 0) thenreturn Time.PRECISION.YEARelseif definition.day == nil or definition.day == 0 thenreturn Time.PRECISION.MONTHelseif definition.hour == nil thenreturn Time.PRECISION.DAYelseif definition.minute == nil thenreturn Time.PRECISION.HOURelseif definition.second == nil thenreturn Time.PRECISION.MINUTEelsereturn Time.PRECISION.SECONDendend--[[Try to find the relevant calendar for a time definition@param table time definition@return string the calendar name]]--local function guessCalendar( definition )if definition.year ~= nil and definition.year < 1583 and definition.precision > Time.PRECISION.MONTH thenreturn Time.CALENDAR.JULIANelsereturn Time.CALENDAR.GREGORIANendend--[[Parse an ISO 2061 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]]--local function parseIso8601( iso, withoutRecurrence )local definition = {}--Split date and timeiso = mw.text.trim( iso:upper() )local beginMatch, endMatch, date, time, offset = iso:find( '([%+%-]?[%d%-]+)[T ]?([%d%.:]*)([Z%+%-]?[%d:]*)' )if beginMatch ~= 1 or endMatch ~= iso:len() then --iso is not a valid ISO stringreturn {}end--dateif date ~= nil thenlocal isBC = falseif date:sub( 1, 1 ) == '-' thenisBC = truedate = date:sub( 2, date:len() )endlocal parts = mw.text.split( date, '-' )if not withoutRecurrence and table.maxn( parts ) == 2 and parts[1]:len() == 2 then--MM-DD casedefinition.month = tonumber( parts[1] )definition.day = tonumber( parts[2] )elseif isBC thendefinition.year = -1 * tonumber( parts[1] )  --FIXME - 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--timeif time ~= nil thenlocal parts = mw.text.split( time, ':' )definition.hour = tonumber( parts[1] )definition.minute = tonumber( parts[2] )definition.second = tonumber( parts[3] )end--ofsetif offset ~= nil thenif offset == 'Z' thendefinition.utcoffset = '+00:00'elsedefinition.utcoffset = offsetendendreturn definitionend--[[Format UTC offset for ISO output@param string offset UTC offset@return string UTC offset for ISO]]--local function formatUtcOffsetForIso( offset )if offset == '+00:00' thenreturn 'Z'elsereturn offsetendend--[[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]]--local function prepend(str, c, length)str = tostring( str )while str:len() < length dostr = c .. strendreturn strend--  LEAP_GREGORIAN  --  Is a given year in the Gregorian calendar a leap year ?local function leapGregorian(year)return ((year % 4) == 0) and(not (((year % 100) == 0) and ((year % 400) ~= 0)))end--  GREGORIAN_TO_JD  --  Determine Julian day number from Gregorian calendar datelocal GREGORIAN_EPOCH = 1721425.5local function gregorianToJd(year, month, day)return (GREGORIAN_EPOCH - 1) +       (365 * (year - 1)) +       math.floor((year - 1) / 4) +       (-math.floor((year - 1) / 100)) +       math.floor((year - 1) / 400) +       math.floor((((367 * month) - 362) / 12) +       ((month <= 2) and 0 or                           (leapGregorian(year) and -1 or -2)       ) +       day)end--  JD_TO_JULIAN  --  Calculate Julian calendar date from Julian daylocal function jdToJulian(td)local z, a, alpha, b, c, d, e, year, month, daytd = td + 0.5z = math.floor(td)a = zb = a + 1524c = math.floor((b - 122.1) / 365.25)d = math.floor(365.25 * c)e = math.floor((b - d) / 30.6001)month = math.floor((e < 14) and (e - 1) or (e - 13))year = math.floor((month > 2) and (c - 4716) or (c - 4715))day = b - d - math.floor(30.6001 * e)--[[If year is less than 1, subtract one to convert froma zero based date system to the common era system inwhich the year -1 (1 B.C.E) is followed by year 1 (1 C.E.).--]]if year < 1 thenyear = year - 1endreturn year, month, dayendlocal function eq(t1, t2)return (t1.calendar == t2.calendar and t1.year == t2.yearand t1.month == t2.month and t1.day == t2.day)endlocal function lt(t1, t2)if t1.calendar ~= t2.calendar then-- error('Eltérő naptárak, nem lehet összehasonlítani', 2)endif t1.year < t2.year thenreturn trueendif t1.year == t2.year thenif t1.month < t2.month thenreturn trueendif t1.month == t2.month and t1.day < t2.day thenreturn trueendendreturn falseendlocal function le(t1, t2)return (t1 == t2 or t1 < t2)end--Public interface--[[Build a new Time@param table definition definition of the time@return Time|nil]]--function Time.new( definition )--Default valuesif definition.precision == nil thendefinition.precision = guessPrecision( definition )endif definition.calendar == nil thendefinition.calendar = guessCalendar( definition )endif not validate( definition ) thenreturn nilendlocal time = {year = definition.year or nil,month = definition.month or 1,day = definition.day or 1,hour = definition.hour or 0,minute = definition.minute or 0,second = definition.second or 0,utcoffset = definition.utcoffset or '+00:00',calendar = definition.calendar or Time.CALENDAR.GREGORIAN,precision = definition.precision or 0}setmetatable( time, {__index = Time,__eq = eq,__lt = lt,__le = le,__tostring = function( self ) return self:toString() end} )return timeend--[[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]]--function Time.newFromIso8601( iso, withoutRecurrence )return Time.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]]--function Time.newFromWikidataValue( wikidataValue )local definition = parseIso8601( wikidataValue.time )definition.precision = wikidataValue.precisionif  wikidataValue.calendarmodel == 'http://www.wikidata.org/entity/Q1985727' thendefinition.calendar = Time.CALENDAR.GREGORIANelseif  wikidataValue.calendarmodel == 'http://www.wikidata.org/entity/Q1985786' thendefinition.calendar = Time.CALENDAR.JULIANelsereturn nilendreturn Time.new( definition )end--[[Return a Time as a ISO 8601 string@return string]]--function Time:toIso8601()local iso = ''if self.year ~= nil thenif self.year < 0 then --Years BC are counted since 0 and not -1iso = '-' .. prepend(string.format('%.0f', -1 * self.year), '0', 4)elseiso = prepend(string.format('%.0f', self.year), '0', 4)endend--monthif self.precision < Time.PRECISION.MONTH thenreturn isoendif self.iso ~= '' theniso = iso .. '-'endiso = iso .. prepend( self.month, '0', 2 )--dayif self.precision < Time.PRECISION.DAY thenreturn isoendiso = iso .. '-' .. prepend( self.day, '0', 2 )--hourif self.precision < Time.PRECISION.HOUR thenreturn isoendiso = iso .. 'T' .. prepend( self.hour, '0', 2 )--minuteif self.precision < Time.PRECISION.MINUTE thenreturn iso .. formatUtcOffsetForIso( self.utcoffset )endiso = iso .. ':' .. prepend( self.minute, '0', 2 )--secondif self.precision < Time.PRECISION.SECOND thenreturn iso .. formatUtcOffsetForIso( self.utcoffset )endreturn iso .. ':' .. 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]]--function Time:toString( language )if language == nil thenlanguage = mw.language.getContentLanguage()elseif type( language ) == 'string' thenlanguage = mw.language.new( language )end--return language:formatDate( 'r', self:toIso8601() )return self:toIso8601()--TODO: improveend--[[Return a Time in HTMl (with a <time> node)@param mw.language|string|nil language to use. By default the content language.@param table|nil attributes table of attributes to add to the <time> node.@return string]]--function Time:toHtml( language, attributes )if attributes == nil thenattributes = {}endattributes['datetime'] = self:toIso8601()return mw.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]]--function Time.knowsPrecision( precision )for _,id in pairs( Time.PRECISION ) doif id == precision thenreturn trueendendreturn falseend--[[Supported calendar models]]--Time.CALENDAR = {GREGORIAN = 'Gregorian',JULIAN    = 'Julian'}--[[Calculate time diff in years between two dates.@param time1 The former date@param time2 The latter date; current date if not given@return number The number of years between the two dates@return string The diff in human-readable format, may be "n-n+1" if the exact number cannot be determined due to the different precisions]]function Time.age(time1, time2)-- Use current date if latter date not givenif time2 == nil thentime2 = Time.newFromIso8601(mw.getContentLanguage():formatDate('c', nil, true), true)endlocal age = time2.year - time1.year-- There is no year 0if time1.year < 0 and time2.year > 0 thenage = age - 1endif time1.precision > Time.PRECISION.MONTH thenif time2.precision > Time.PRECISION.MONTH thenif time2.month < time1.month thenage = age - 1elseif time2.month == time1.month and time2.day < time1.day thenage = age - 1endreturn age, tostring(age)elseif time2.precision == Time.PRECISION.MONTH thenif time2.month == time1.month thenreturn age - 1, (age-1) .. '-' .. ageendif time2.month < time1.month thenage = age - 1endreturn age, tostring(age)endelseif time1.precision == Time.PRECISION.MONTH thenif time2.precision > Time.PRECISION.YEAR thenif time2.month == time1.month thenreturn age, (age-1) .. '-' .. ageendif time2.month < time1.month thenage = age - 1endreturn age, tostring(age)endendreturn age, (age-1) .. '-' .. ageend--TODO Átszervezni, befejeznifunction Time:formatDate(options)options = options or {}local fd = ''if self.precision >= Time.PRECISION.DAY thenfd = self.year < 0 and 'i. e. ' .. (-1 * self.year) or fd .. self.yearif options.link ~= 'nem' then fd = '[[' .. fd .. ']]' endlocal d = '2000-' .. prepend(self.month, '0', 2) .. '-' .. prepend(self.day, '0', 2)  -- kamu évlocal lang = mw.getContentLanguage()fd = fd .. '. ' .. lang:formatDate(options.link == 'nem' and 'F"&nbsp;"j.' or '[[F j.|F"&nbsp;"j.]]', d)elseif self.precision >= Time.PRECISION.MONTH thenfd = self.year < 0 and 'i. e. ' .. (-1 * self.year) or fd .. self.yearlocal month = mw.getContentLanguage():formatDate('F', '2000-' .. self.month)if options.link ~= 'nem' then fd = '[[' .. fd .. ']]' endfd = fd .. '. ' .. monthelseif self.precision >= Time.PRECISION.YEAR thenfd = self.year < 0 and 'i. e. ' .. (-1 * self.year) or fd .. self.yearif options.link ~= 'nem' then fd = '[[' .. fd .. ']]' endelseif self.precision == Time.PRECISION.YEAR10 thenlocal year = math.floor((self.year < 0 and -1 * self.year or self.year)  / 10) * 10local suffixesRoundBelow100 = {'es', 'as', 'as', 'es', 'es', 'as', 'es', 'as', 'es'}fd = self.year < 0 and 'i. e. ' .. year or tostring(year)if year % 10000 == 0 then fd = fd .. '-s'elseif year % 1000 == 0 then fd = fd .. '-es'elseif year % 100 == 0 then fd = fd .. '-as'else fd = fd .. '-' .. suffixesRoundBelow100[year % 100 / 10] endfd = fd .. ' évek'if options.link ~= 'nem' then fd = '[[' .. fd .. ']]' endelseif self.precision == Time.PRECISION.YEAR100 thenif self.year < 0 thenfd = 'i. e. ' .. math.ceil(-1 * self.year / 100) .. '. század'elsefd = math.ceil(self.year / 100) .. '. század'endif options.link ~= 'nem' then fd = '[[' .. fd .. ']]' endelseif self.precision == Time.PRECISION.KY thenif self.year < 0 thenfd = 'i. e. ' .. math.ceil(-1 * self.year / 1000) .. '. évezred'elsefd = math.ceil(self.year / 1000) .. '. évezred'endif options.link ~= 'nem' then fd = '[[' .. fd .. ']]' endelsefd = tostring(self.year)endif options['életkor'] == 'igen' and self.precision >= Time.PRECISION.YEAR thenlocal property = string.upper(options.property)if property == 'P570' then  -- halálozási dátumlocal claim = mw.wikibase.getEntity():getBestStatements('P569')[1]if claim and claim.mainsnak.snaktype == 'value' and claim.mainsnak.datavalue.value.precision >= Time.PRECISION.YEAR thenlocal time = Time.newFromWikidataValue(claim.mainsnak.datavalue.value)local _, age = Time.age(time, self)fd = fd .. ' ' .. mw.text.tag('span', {style = 'white-space:nowrap;'}, '(' .. age .. ' évesen)')endelseif property == 'P569' then  -- születési dátumif not mw.wikibase.getEntity().claims['P570'] thenfd = fd .. ' ' .. mw.text.tag('span', {style = 'white-space:nowrap;'}, '(' .. (Time.age(self)) .. ' éves)')endendendreturn fdendreturn Time