יחידה:תאריך
ניתן ליצור תיעוד על היחידה הזאת בדף יחידה:תאריך/תיעוד
local Date = {} local maxDaysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} --[[ Supported calendar models ]]-- Date.CALENDAR = { GREGORIAN = 'Gregorian', JULIAN = 'Julian' } --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 <= max end --[[ Validate a time defintion @param table definition data @return boolean ]]-- local function validate(definition) --Validate constants if not Date.knowsPrecision(definition.precision) or (definition.calendar ~= Date.CALENDAR.GREGORIAN and definition.calendar ~= Date.CALENDAR.JULIAN) then return false end --Validate year if not (type( definition.year ) == 'number' or (definition.year == nil and precision == Date.PRECISION.DAY)) then return false end if definition.precision <= Date.PRECISION.YEAR then return true end --Validate month if not validateNumberInRange( definition.month, 1, 12 ) then return false end if definition.precision <= Date.PRECISION.MONTH then return true end --Validate day if not validateNumberInRange( definition.day, 1, 31 ) then return false end if definition.precision <= Date.PRECISION.DAY then return true end --Validate hour if not validateNumberInRange( definition.hour, 0, 23 ) then return false end if definition.precision <= Date.PRECISION.HOUR then return true end --Validate minute if not validateNumberInRange( definition.minute, 0, 59 ) then return false end if definition.precision <= Date.PRECISION.MINUTE then return true end --Validate second if not validateNumberInRange( definition.second, 0, 60 ) then return false end return true end --[[ 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) then return Date.PRECISION.YEAR elseif definition.day == nil or definition.day == 0 then return Date.PRECISION.MONTH elseif definition.hour == nil then return Date.PRECISION.DAY elseif definition.minute == nil then return Date.PRECISION.HOUR elseif definition.second == nil then return Date.PRECISION.MINUTE else return Date.PRECISION.SECOND end end --[[ 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 > Date.PRECISION.MONTH then return Date.CALENDAR.JULIAN else return Date.CALENDAR.GREGORIAN end end --[[ 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 time iso = 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 string return {} end --date if date ~= nil then local isBC = false if date:sub( 1, 1 ) == '-' then isBC = true date = date:sub( 2, date:len() ) end local parts = mw.text.split( date, '-' ) if not withoutRecurrence and table.maxn( parts ) == 2 and parts[1]:len() == 2 then --MM-DD case definition.month = tonumber( parts[1] ) definition.day = tonumber( parts[2] ) else if isBC then definition.year = -1 * tonumber( parts[1] ) --FIXME - 1 --Years BC are counted since 0 and not -1 else definition.year = tonumber( parts[1] ) end definition.month = tonumber( parts[2] ) definition.day = tonumber( parts[3] ) end end --time if time ~= nil then local parts = mw.text.split( time, ':' ) definition.hour = tonumber( parts[1] ) definition.minute = tonumber( parts[2] ) definition.second = tonumber( parts[3] ) end --ofset if offset ~= nil then if offset == 'Z' then definition.utcoffset = '+00:00' else definition.utcoffset = offset end end return definition end --[[ 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' then return 'Z' else return offset end end --[[ 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 do str = c .. str end return str end -- 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 local isDateInLeapYear = function(indate) if indate.calendar == Date.CALENDAR.JULIAN then return 0 == indate.year % 4 end return leapGregorian(indate.year) end -- GREGORIAN_TO_JD -- Determine Julian day number from Gregorian calendar date local GREGORIAN_EPOCH = 1721425.5 local 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 day local function jdToJulian(td) local z, a, alpha, b, c, d, e, year, month, day td = td + 0.5 z = math.floor(td) a = z b = a + 1524 c = 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 from a zero based date system to the common era system in which the year -1 (1 B.C.E) is followed by year 1 (1 C.E.). --]] if year < 1 then year = year - 1 end return year, month, day end -- adapted from ro:Modul:GregorianDate local initialOffset = -3 local limitDates = { {year = 4, month = 3, day = 3, calendar = Date.CALENDAR.JULIAN }, {year = 100, month = 3, day = 2, calendar = Date.CALENDAR.JULIAN }, {year = 200, month = 3, day = 1, calendar = Date.CALENDAR.JULIAN }, {year = 300, month = 2, day = 29, calendar = Date.CALENDAR.JULIAN }, {year = 500, month = 2, day = 28, calendar = Date.CALENDAR.JULIAN }, {year = 600, month = 2, day = 27, calendar = Date.CALENDAR.JULIAN }, {year = 700, month = 2, day = 26, calendar = Date.CALENDAR.JULIAN }, {year = 900, month = 2, day = 25, calendar = Date.CALENDAR.JULIAN }, {year = 1000, month = 2, day = 24, calendar = Date.CALENDAR.JULIAN }, {year = 1100, month = 2, day = 23, calendar = Date.CALENDAR.JULIAN }, {year = 1300, month = 2, day = 22, calendar = Date.CALENDAR.JULIAN }, {year = 1400, month = 2, day = 21, calendar = Date.CALENDAR.JULIAN }, {year = 1500, month = 2, day = 20, calendar = Date.CALENDAR.JULIAN }, {year = 1700, month = 2, day = 19, calendar = Date.CALENDAR.JULIAN }, {year = 1800, month = 2, day = 18, calendar = Date.CALENDAR.JULIAN }, {year = 1900, month = 2, day = 17, calendar = Date.CALENDAR.JULIAN }, {year = 2100, month = 2, day = 16, calendar = Date.CALENDAR.JULIAN }, {year = 2200, month = 2, day = 15, calendar = Date.CALENDAR.JULIAN }, {year = 2300, month = 2, day = 14, calendar = Date.CALENDAR.JULIAN } } function Date.julianToGregorian(indate) if indate.calendar ~= Date.CALENDAR.JULIAN then return indate end local outputDate if indate.precision > Date.PRECISION.MONTH then local offset = initialOffset local limitDateIdx = 1 while limitDateIdx < #limitDates and Date.le(limitDates[limitDateIdx], indate) do limitDateIdx = limitDateIdx + 1 offset = offset + 1 end outputDate = Date.addDaysToDate(indate, offset) else outputDate = mw.clone(indate) end outputDate.calendar = Date.CALENDAR.GREGORIAN outputDate.calendarmodel = 'http://www.wikidata.org/entity/Q1985727' return Date.new(outputDate) end function Date.addDaysToDate(indate, days) local outdate = mw.clone(indate) outdate.day = outdate.day + days local lastDayOfMonth = maxDaysInMonth[outdate.month] while outdate.day > lastDayOfMonth do lastDayOfMonth = maxDaysInMonth[outdate.month] if outdate.month == 2 and isDateInLeapYear(outdate) then lastDayOfMonth = 29 end outdate.month = outdate.month + 1 outdate.day = outdate.day - lastDayOfMonth end while outdate.month > 12 do outdate.year = outdate.year + 1 outdate.month = outdate.month - 12 end return outdate end function Date.le(t1, t2, correct_calender) if t1.calendar ~= t2.calendar then if correct_calender then t1 = Date.julianToGregorian(t1) t2 = Date.julianToGregorian(t2) else error("Calanders dont match", 2) end end if t1.year < t2.year then return true end if t1.year == t2.year then if t1.month < t2.month then return true end if t1.month == t2.month and t1.day <= t2.day then return true end end return false end --Public interface --[[ Build a new Date @param table definition definition of the time @return Date|nil ]]-- function Date.new( definition ) --Default values if definition.precision == nil then definition.precision = guessPrecision( definition ) end if definition.calendar == nil then definition.calendar = guessCalendar( definition ) end if not validate( definition ) then return nil end local 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 Date.CALENDAR.GREGORIAN, precision = definition.precision or 0 } setmetatable( time, { __index = Date, __le = le, __tostring = function( self ) return self:toString() end } ) return time end --[[ Build a new Date 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 Date|nil ]]-- function Date.newFromIso8601( iso, withoutRecurrence ) return Date.new( parseIso8601( iso, withoutRecurrence ) ) end --[[ Build a new Date from a Wikidata time value @param table wikidataValue the time as represented by Wikidata @return Date|nil ]]-- function Date.newFromWikidataValue( wikidataValue ) local definition = parseIso8601( wikidataValue.time ) definition.precision = wikidataValue.precision if wikidataValue.calendarmodel == 'http://www.wikidata.org/entity/Q1985727' then definition.calendar = Date.CALENDAR.GREGORIAN elseif wikidataValue.calendarmodel == 'http://www.wikidata.org/entity/Q1985786' then definition.calendar = Date.CALENDAR.JULIAN else return nil end return Date.new( definition ) end --[[ Build a new Date from a wiki string @param string wikitext string @return Date|nil ]] function Date.newFromWikitext( wikitext ) local months = { ['ינואר']= 1, ['פברואר']= 2, ['מרץ']= 3, ['אפריל']= 4, ['מאי']= 5, ['יוני']= 6, ['יולי']= 7, ['אוגוסט']= 8, ['ספטמבר']= 9, ['אוקטובר']= 10, ['נובמבר']= 11, ['דצמבר']= 12 } local calendar = nil if mw.ustring.find( wikitext, '<small>%(%[%[הלוח היוליאני%|יוליאני%]%]%)</small>' ) then calendar = Date.CALENDAR.JULIAN wikitext = mw.ustring.gsub( wikitext, "<small>%(%[%[הלוח היוליאני%|יוליאני%]%]%)</small>", "" ) end -- Remove instances of [ and ] wikitext = mw.ustring.gsub( wikitext, "[%[%]]", "" ) -- Remove footnotes & directionality markers wikitext = mw.text.killMarkers( wikitext ) wikitext = mw.ustring.gsub(wikitext, "‏","") wikitext = mw.ustring.gsub(wikitext, "‎","") -- BC to minus wikitext = mw.ustring.gsub( wikitext, "([0-9]+) לפנה[\"״]ס" , "-%1") for a in pairs(months) do wikitext = mw.ustring.gsub(wikitext, ' ?ב?'..a, ' ' .. months[a]) end if mw.ustring.match(wikitext, '^המאה ה[־-]%d+$') then local yearStr = mw.ustring.match(wikitext, '^המאה ה[־-](%d+)$') return Date.new( { year=tonumber(yearStr)*100, month=0, day=0, precision= Date.PRECISION.YEAR100 } ) end -- if there are alphabet chars return nil (unexpected character) assert(not mw.ustring.find(wikitext, '%a'), "Unexpected format") local parts = mw.text.split(mw.text.trim(wikitext),' ') local definition = {} definition.calendar = calendar if #parts==3 then -- DMY date definition.year = tonumber(parts[3]) definition.month = tonumber(parts[2]) definition.day = tonumber(parts[1]) assert(definition.year, "Could not recognize year") assert(definition.month<13 and definition.month>0, "Could not recognize month number") assert(definition.day<32 and definition.day>0, "Wrong date format") definition.precision = Date.PRECISION.DAY elseif #parts==2 then -- MY date definition.year = tonumber(parts[2]) definition.month = tonumber(parts[1]) definition.precision = Date.PRECISION.MONTH assert(definition.year<1e7, "Could not recognize year") assert(definition.month<13 and definition.month>0, "Could not recognize month number") elseif #parts==1 then --Y date definition.precision = Date.PRECISION.YEAR definition.year=tonumber(parts[1]) assert(definition.year<1e7, "Could not recognize year") else error("Unexpected date format") end return Date.new( definition ) end --[[ Return a Date as a ISO 8601 string @return string ]]-- function Date:toIso8601() local iso = '' if self.year ~= nil then if self.year < 0 then --Years BC are counted since 0 and not -1 iso = '-' .. prepend(string.format('%.0f', -1 * self.year), '0', 4) else iso = prepend(string.format('%.0f', self.year), '0', 4) end end --month if self.precision < Date.PRECISION.MONTH then return iso end if self.iso ~= '' then iso = iso .. '-' end iso = iso .. prepend( self.month, '0', 2 ) --day if self.precision < Date.PRECISION.DAY then return iso end iso = iso .. '-' .. prepend( self.day, '0', 2 ) --hour if self.precision < Date.PRECISION.HOUR then return iso end iso = iso .. 'T' .. prepend( self.hour, '0', 2 ) --minute if self.precision < Date.PRECISION.MINUTE then return iso .. formatUtcOffsetForIso( self.utcoffset ) end iso = iso .. ':' .. prepend( self.minute, '0', 2 ) --second if self.precision < Date.PRECISION.SECOND then return iso .. formatUtcOffsetForIso( self.utcoffset ) end return iso .. ':' .. prepend( self.second, '0', 2 ) .. formatUtcOffsetForIso( self.utcoffset ) end --[[ Return a hebrew representation of Date as a string @return string ]]-- function Date:toHebrewString() local hebrewStr = '' local year = self.year if (self.precision >= Date.PRECISION.MY100) and (self.precision <= Date.PRECISION.MY) then if self.year>0 then return (self.year/1000000) .. ' מיליון שנים לספירה' else return (-self.year/1000000) ..' מיליון שנים לפנה״ס' end elseif (self.precision >=Date.PRECISION.KY100) and (self.precision <= Date.PRECISION.KY) then if self.year>0 then return 'האלף ה־'.. (self.year/1000) else return 'האלף ה־'.. (-self.year/1000) ..' לפנה״ס' end elseif self.precision == Date.PRECISION.YEAR100 then if year>0 then return 'המאה ה־'.. math.ceil(self.year/100) else return 'המאה ה־'.. math.ceil(-self.year/100) ..' לפנה״ס' end elseif self.precision == Date.PRECISION.YEAR10 then local year = math.floor((self.year < 0 and -1 * self.year or self.year) / 10) * 10 if self.year>0 then if year%100==0 then return 'העשור הראשון של המאה ה־'.. tostring((year/100)+1) else return 'שנות ה־' .. tostring(year%100) .. ' של המאה ה־'.. tostring(math.ceil(year/100)) end else if year%100==0 then return 'העשור הראשון של המאה ה־'.. tostring((year/100))..' לפנה״ס' else return 'שנות ה־' .. tostring(year%100) .. ' של המאה ה־'.. tostring(math.ceil(year/100))..' לפנה״ס' end end end if self.year ~= nil then if self.year < 0 then hebrewStr = mw.ustring.format('%d לפנה״ס', (-1*self.year)) else if self.calendar == Date.CALENDAR.JULIAN and self.year > 1583 then hebrewStr = mw.ustring.format('%d <small>([[הלוח היוליאני|יוליאני]])</small>', (self.year)) else hebrewStr = mw.ustring.format('%d', self.year) end end end --month if self.precision>=Date.PRECISION.YEAR and self.precision < Date.PRECISION.MONTH then return hebrewStr end local months = { 'ינואר','פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר','דצמבר' } hebrewStr = months[self.month] .. ' ' .. hebrewStr --day if self.precision < Date.PRECISION.DAY then return hebrewStr end hebrewStr = mw.ustring.format('%d ב%s', self.day, hebrewStr) --hour if self.precision < Date.PRECISION.HOUR then return hebrewStr end hebrewStr = mw.ustring.format('%s בשעה %d', hebrewStr, self.hour) --minute if self.precision < Date.PRECISION.MINUTE then return hebrewStr .. formatUtcOffsetForIso( self.utcoffset ) end hebrewStr = hebrewStr .. ':' .. prepend( self.minute, '0', 2 ) --second if self.precision < Date.PRECISION.SECOND then return hebrewStr .. formatUtcOffsetForIso( self.utcoffset ) end return hebrewStr .. ':' .. prepend( self.second, '0', 2 ) .. formatUtcOffsetForIso( self.utcoffset ) end --[[ Return a Date as a string @param mw.language|string|nil language to use. By default the content language. @return string ]]-- function Date:toString( language ) if language == nil then return self:toIso8601() end if language == 'he' then return self:toHebrewString() end --[[if type( language ) == 'string' then language = mw.language.new( language ) end return language:formatDate( 'r', self:toIso8601() )]] return self:toIso8601() end --[[ Return a Date 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 Date:toHtml( language, attributes ) if attributes == nil then attributes = {} end attributes['datetime'] = self:toIso8601() return mw.text.tag( 'time', attributes, self:toString( language ) ) end --[[ All possible precisions for a Date (same ids as Wikibase) ]]-- Date.PRECISION = { GY = 0, --Gigayear MY100 = 1, --100 Megayears MY10 = 2, --10 Megayears MY = 3, --Megayear KY100 = 4, --100 Kiloyears KY10 = 5, --10 Kiloyears KY = 6, --Kiloyear YEAR100 = 7, --100 years YEAR10 = 8, --10 years YEAR = 9, MONTH = 10, DAY = 11, HOUR = 12, MINUTE = 13, SECOND = 14 } --[[ Check if the precision is known @param number precision ID @return boolean ]]-- function Date.knowsPrecision( precision ) for _,id in pairs( Date.PRECISION ) do if id == precision then return true end end return false end function Date.age(time1, time2) if time2 == nil then time2 = Date.newFromIso8601(mw.getContentLanguage():formatDate('c', nil, true), true) end local age = {year, month, day} age.year = time2.year - time1.year age.month = time2.month - time1.month age.day = time2.day - time1.day if age.day < 0 then local lastMonth = time2.month - 1 if lastMonth == 0 then lastMonth = 12 end age.day = age.day + maxDaysInMonth[lastMonth] age.month = age.month - 1 end if age.month < 0 then age.month = age.month + 12 age.year = age.year - 1 end if time1.year < 0 and time2.year > 0 then age.year = age.year - 1 end return age end function Date:formatDate(options) options = options or {} local fd = '' if self.precision >= Date.PRECISION.DAY then fd = self.year < 0 and (-1 * self.year) .. ' לפנה"ס' or fd .. self.year if options.link then fd = '[[' .. fd .. ']]' end local d = '2000-' .. prepend(self.month, '0', 2) .. '-' .. prepend(self.day, '0', 2) local lang = mw.getContentLanguage() fd = fd .. '. ' .. lang:formatDate(options.link and '[[j xg]]' or 'j xg', d) elseif self.precision >= Date.PRECISION.MONTH then fd = self.year < 0 and (-1 * self.year) .. ' לפנה"ס' or fd .. self.year local month = mw.getContentLanguage():formatDate('F', '2000-' .. self.month) if options.link then fd = '[[' .. fd .. ']]' end fd = month .. ' ' .. fd elseif self.precision >= Date.PRECISION.YEAR then fd = self.year < 0 and (-1 * self.year) .. ' לפנה"ס' or fd .. self.year if options.link ~= 'nem' then fd = '[[' .. fd .. ']]' end elseif self.precision == Date.PRECISION.YEAR10 then local year = math.floor((self.year < 0 and -1 * self.year or self.year) / 10) * 10 fd = 'שנות ה-' .. tostring(year%100) .. ' של המאה ה-'.. tostring(ceil(year/100)) fd = self.year < 0 and year .. ' לפנה"ס' or tostring(year) elseif self.precision == Date.PRECISION.YEAR100 then if self.year < 0 then fd = 'המאה ה-' .. math.floor(-1 * self.year / 100) .. ' לפנה"ס' else fd = 'המאה ה-' ..math.floor(self.year / 100) end if options.link then fd = '[[' .. fd .. ']]' end else fd = tostring(self.year) end return fd end function parseStrDate(dateStr, dateType) local datetime = Date.newFromWikitext( dateStr ) if datetime.precision >= Date.PRECISION.DAY then -- DMY date if dateType=='Y' then res = datetime.year elseif dateType=='M' then res = datetime.month elseif dateType=='D' then res = datetime.day elseif dateType == 'TS' then res = datetime:toIso8601() end elseif datetime.precision >= Date.PRECISION.MONTH then -- MY date if dateType=='Y' then res = datetime.year elseif dateType=='M' then res = datetime.month elseif dateType == 'TS' then res = datetime:toIso8601() end else --Y date if dateType=='Y' then res = datetime.year elseif dateType == 'TS' then res = datetime:toIso8601() end end return res end function parseDateRange(dateRangeStr, diffFormat, inclusive ) -- remove footnotes dateRangeStr = mw.text.killMarkers(dateRangeStr) dateRangeStr = mw.ustring.gsub(dateRangeStr, "‏","") local outputPrefix = '' local parts = mw.text.split(dateRangeStr,' *[–%-] *') assert(#parts==2 or #parts==1, "Date range expected format is from - to or from (e.g from - now)") -- parse dates local t1 = Date.newFromWikitext( parts[1] ) local t2 local useCurrent = #parts<2 or (parts[2] == 'היום' or parts[2]=='הווה') if not useCurrent then t2 = Date.newFromWikitext( parts[2] ) else t2 = Date.newFromIso8601(mw.getContentLanguage():formatDate('c', nil, true), true) end local hasYears = (diffFormat=='auto') local hasDays = (diffFormat=='auto') for i=1,#diffFormat do if (diffFormat[i]=='years') then hasYears=true elseif diffFormat[i]=='days' then hasDays =true end end if hasDays and ((t1.precision>=Date.PRECISION.MONTH and t2.precision<Date.PRECISION.MONTH) or (t1.precision<Date.PRECISION.MONTH and t2.precision>=Date.PRECISION.MONTH)) then -- Ambiguous date range if t2.year - t1.year > 2 then diffFormat = {'years'} else return '' end end local NO_GUESS, MONTH_GUESS, DAY_GUESS = 0, 1, 2 local guessLevel = NO_GUESS if t1.precision<Date.PRECISION.MONTH or t2.precision<Date.PRECISION.MONTH then guessLevel = MONTH_GUESS inclusive=true elseif t1.precision<Date.PRECISION.DAY or t2.precision<Date.PRECISION.DAY then guessLevel = DAY_GUESS end local t1 = os.time({ year = t1.year, month = t1.month or 6, day = t1.day or 16 }) t2= os.time({ year = t2.year, month = t2.month or 6, day = t2.day or 16 }) local dif = os.difftime (t2, t1) local lang = mw.getContentLanguage() local readableInterval = lang:getDurationIntervals(dif, {'years', 'days'}) readableInterval['days'] = readableInterval['days'] or 0 readableInterval['years'] = readableInterval['years'] or 0 if not (guessLevel==NO_GUESS) and not (guessLevel==DAY_GUESS and hasYears and #diffFormat==1 and readableInterval['days']>31) then outputPrefix='כ־' end if inclusive then dif = dif+60*60*24 -- include last day end if diffFormat=="auto" then if dif<=60*60*24 then return '' -- Ambiguous date range - we arent handling preceision of less than 1 day (hours, minutes, seconds) end if guessLevel==MONTH_GUESS and readableInterval['years']==0 then return '' -- Ambiguous date range end --for intervals of around year if readableInterval['years']>0 and (readableInterval['days']<30 or (365-readableInterval['days'])<30) then -- around if readableInterval['days']<30 then dif = dif - readableInterval['days']*(60*60*24) else dif = dif+((365-readableInterval['days'])*(60*60*24)) end diffFormat = {'years'} else local diffDays = dif/(60*60*24) if diffDays<7*3 then diffFormat = { 'days' } elseif diffDays<364 then diffFormat = {'weeks', 'days'} elseif diffDays<10*365 then diffFormat = {'years', 'weeks'} else diffFormat = {'years'} end end end if diffFormat=="raw" then return dif else local res = outputPrefix..lang:formatDuration(dif, diffFormat) -- post process formatDuration which is not good enough res= mw.ustring.gsub(res,"כ־([א-ת])","כ%1") res= mw.ustring.gsub(res,"וגם ([0-9])","ו־%1") res= mw.ustring.gsub(res,"וגם ([א-ת])","ו%1") return res end end function parseDateRangeSafe(frame) local diffFormat = 'auto' if frame.args[2] == 'ימים' then diffFormat = {'days'} elseif frame.args[2] == 'שנים' then diffFormat = {'years'} elseif frame.args[2] == "הפרש" then diffFormat = "raw" elseif frame.args[2] == "גיל" then diffFormat = {'years'} elseif frame.args[2] == "מספר" then diffFormat = {'years'} end local inclusive = (frame.args["כולל"]=="כן") local success, res = pcall(parseDateRange, frame.args[1], diffFormat, inclusive) if success then local str=res -- the following translations are needed because the underline function -- local format is wierd str = mw.ustring.gsub(str, "(כ)־([א-ת])", "%1%2") if frame.args[2] == "גיל" then str= mw.ustring.gsub(str,"כ־(.+) שנים","%1 בערך") str= mw.ustring.gsub(str," שנים","") end -- This parameter returns the difference as number of years, without any text. if frame.args[2] == "מספר" then str= mw.ustring.gsub(str,"כ(.+)","%1"); str= mw.ustring.gsub(str,"־(.+)","%1"); str= mw.ustring.gsub(str," שנים","") if str == "שנתיים" then str = 2 end if str == "שנה" then str = 1 end str = mw.ustring.gsub(str," שנה", "") if tonumber(str) > 0 and tonumber(parseDateRange(frame.args[1], "raw", inclusive)) < 0 then str = -1 * str end end return str else return frame.args['error'] or '<span class="scribunto-error">שגיאת תאריך: '..res..'</span>[[קטגוריה:דפים עם שגיאות בתאריך]]' end end function parseStrDateSafe(frame) local dateType = frame.args[2] if dateType =='שנה' then dateType = 'Y' elseif dateType=='חודש' then dateType = 'M' elseif dateType=='יום' then dateType='D' end local success, res = pcall( parseStrDate, frame.args[1], dateType ) if success then if dateType=='Y' and mw.ustring.sub( res, 0, 1)=='-' then res = mw.ustring.sub( res, 2).. ' לפנה"ס' end return res else return frame.args['error'] or '<span class="scribunto-error">שגיאת תאריך: '..res..'</span>[[קטגוריה:דפים עם שגיאות בתאריך]]' end end Date['חשב'] = parseStrDateSafe; Date['חשב טווח'] = parseDateRangeSafe; Date['parseDateRange'] = parseDateRange; return Date