יחידה:תאריך: הבדלים בין גרסאות בדף
מראה
חופים הם לפעמים געגועים לנחל. ראיתי פעם חוף שנחל עזבו עם לב שבור של חול ואבן. והאדם, והאדם הוא לפעמים גם כן יכול להישאר נטוש ובלי כוחות ממש |
מ 3 גרסאות של הדף wikipedia:he:יחידה:תאריך יובאו |
||
| (43 גרסאות ביניים של 6 משתמשים אינן מוצגות) | |||
| שורה 1: | שורה 1: | ||
local Date = {} | 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 | --Internal functions | ||
| שורה 151: | שורה 160: | ||
local parts = mw.text.split( time, ':' ) | local parts = mw.text.split( time, ':' ) | ||
definition.hour = tonumber( parts[1] ) | definition.hour = tonumber( parts[1] ) | ||
definition.minute = tonumber( parts[ | definition.minute = tonumber( parts[2] ) | ||
definition.second = tonumber( parts[3] ) | definition.second = tonumber( parts[3] ) | ||
end | end | ||
-- | --offset | ||
if offset ~= nil then | if offset ~= nil then | ||
if offset == 'Z' then | if offset == 'Z' then | ||
| שורה 199: | שורה 208: | ||
return ((year % 4) == 0) and | return ((year % 4) == 0) and | ||
(not (((year % 100) == 0) and ((year % 400) ~= 0))) | (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 | end | ||
| שורה 247: | שורה 263: | ||
end | end | ||
local function le(t1, t2) | -- 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 t1.calendar ~= t2.calendar then | ||
if correct_calender then | |||
t1 = Date.julianToGregorian(t1) | |||
t2 = Date.julianToGregorian(t2) | |||
else | |||
error("Calendars don't match", 2) | |||
end | |||
end | end | ||
if t1.year < t2.year then | if t1.year < t2.year then | ||
| שורה 355: | שורה 444: | ||
['דצמבר']= 12 | ['דצמבר']= 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 ] | -- Remove instances of [ and ] | ||
wikitext = mw.ustring.gsub( wikitext, "[%[%]]", "" ) | wikitext = mw.ustring.gsub( wikitext, "[%[%]]", "" ) | ||
| שורה 363: | שורה 456: | ||
wikitext = mw.ustring.gsub(wikitext, "‏","") | wikitext = mw.ustring.gsub(wikitext, "‏","") | ||
wikitext = mw.ustring.gsub(wikitext, "‎","") | wikitext = mw.ustring.gsub(wikitext, "‎","") | ||
-- BC to minus | -- BC to minus | ||
wikitext = mw.ustring.gsub( wikitext, "([0-9]+) לפנה\"ס" , "-%1") | wikitext = mw.ustring.gsub( wikitext, "([0-9]+) לפנה[\"״]ס" , "-%1") | ||
for a in pairs(months) do | for a in pairs(months) do | ||
wikitext = mw.ustring.gsub(wikitext, 'ב?'..a, months[a]) | 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 | end | ||
-- if there are alphabet chars return nil (unexpected character) | -- if there are alphabet chars return nil (unexpected character) | ||
assert(not mw.ustring.find(wikitext, '%a'), "Unexpected format") | assert(not mw.ustring.find(wikitext, '%a'), "Unexpected format") | ||
local parts = mw.text.split(mw.text.trim(wikitext),' ') | |||
local parts = mw.text.split(wikitext,' ') | |||
local definition = {} | local definition = {} | ||
definition.calendar = calendar | |||
if #parts==3 then -- DMY date | if #parts==3 then -- DMY date | ||
definition.year = tonumber(parts[3]) | definition.year = tonumber(parts[3]) | ||
| שורה 451: | שורה 548: | ||
end | end | ||
return iso .. ':' .. prepend( self.second, '0', 2 ) .. formatUtcOffsetForIso( self.utcoffset ) | 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 | end | ||
| שורה 460: | שורה 644: | ||
function Date:toString( language ) | function Date:toString( language ) | ||
if language == nil then | if language == nil then | ||
language = | return self:toIso8601() | ||
end | |||
if language == 'he' then | |||
return self:toHebrewString() | |||
end | |||
--[[if type( language ) == 'string' then | |||
language = mw.language.new( language ) | language = mw.language.new( language ) | ||
end | end | ||
return language:formatDate( 'r', self:toIso8601() )]] | |||
return self:toIso8601() | return self:toIso8601() | ||
end | end | ||
| שורה 517: | שורה 705: | ||
return false | return false | ||
end | end | ||
function Date.age(time1, time2) | function Date.age(time1, time2) | ||
| שורה 530: | שורה 710: | ||
time2 = Date.newFromIso8601(mw.getContentLanguage():formatDate('c', nil, true), true) | time2 = Date.newFromIso8601(mw.getContentLanguage():formatDate('c', nil, true), true) | ||
end | 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 | if time1.year < 0 and time2.year > 0 then | ||
age = age - 1 | age.year = age.year - 1 | ||
end | end | ||
return age | |||
end | end | ||
function Date:formatDate(options) | function Date:formatDate(options) | ||
| שורה 610: | שורה 802: | ||
function parseDateRange(dateRangeStr, diffFormat, inclusive ) | function parseDateRange(dateRangeStr, diffFormat, inclusive ) | ||
-- remove footnotes | -- remove footnotes | ||
dateRangeStr = mw. | dateRangeStr = mw.text.killMarkers(dateRangeStr) | ||
dateRangeStr = mw.ustring.gsub(dateRangeStr, "‏","") | dateRangeStr = mw.ustring.gsub(dateRangeStr, "‏","") | ||
local outputPrefix = '' | local outputPrefix = '' | ||
local parts = mw.text.split(dateRangeStr,' | 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)") | assert(#parts==2 or #parts==1, "Date range expected format is from - to or from (e.g from - now)") | ||
| שורה 620: | שורה 812: | ||
local t1 = Date.newFromWikitext( parts[1] ) | local t1 = Date.newFromWikitext( parts[1] ) | ||
local t2 | local t2 | ||
local useCurrent = #parts<2 or (parts[2] == 'היום' or parts[2]=='הווה') | |||
if not useCurrent then | |||
t2 = Date.newFromWikitext( parts[2] ) | t2 = Date.newFromWikitext( parts[2] ) | ||
else | else | ||
| שורה 637: | שורה 831: | ||
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 | 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 | end | ||
local NO_GUESS, MONTH_GUESS, DAY_GUESS = 0, 1, 2 | local NO_GUESS, MONTH_GUESS, DAY_GUESS = 0, 1, 2 | ||
| שורה 647: | שורה 846: | ||
guessLevel = DAY_GUESS | guessLevel = DAY_GUESS | ||
end | end | ||
local t1 = os.time({ | local t1 = os.time({ | ||
year = t1.year, | year = t1.year, | ||
| שורה 671: | שורה 870: | ||
end | end | ||
if diffFormat=="auto" then | 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 | if guessLevel==MONTH_GUESS and readableInterval['years']==0 then | ||
return '' -- Ambiguous date range | return '' -- Ambiguous date range | ||
| שורה 679: | שורה 880: | ||
if readableInterval['years']>0 and (readableInterval['days']<30 or (365-readableInterval['days'])<30) then | if readableInterval['years']>0 and (readableInterval['days']<30 or (365-readableInterval['days'])<30) then | ||
-- around | -- around | ||
dif = dif- | if readableInterval['days']<30 then | ||
dif = dif - readableInterval['days']*(60*60*24) | |||
else | |||
dif = dif+((365-readableInterval['days'])*(60*60*24)) | |||
end | |||
diffFormat = {'years'} | diffFormat = {'years'} | ||
else | else | ||
| שורה 689: | שורה 894: | ||
end | end | ||
end | end | ||
end | end | ||
if diffFormat=="raw" then | if diffFormat=="raw" then | ||
return dif | return dif | ||
else | 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 | ||
end | end | ||
| שורה 704: | שורה 914: | ||
elseif frame.args[2] == 'שנים' then | elseif frame.args[2] == 'שנים' then | ||
diffFormat = {'years'} | diffFormat = {'years'} | ||
elseif frame.args[2] == 'שנים וימים' then | |||
diffFormat = {'years', 'days'} | |||
elseif frame.args[2] == "הפרש" then | elseif frame.args[2] == "הפרש" then | ||
diffFormat = "raw" | diffFormat = "raw" | ||
| שורה 711: | שורה 923: | ||
diffFormat = {'years'} | diffFormat = {'years'} | ||
end | end | ||
local inclusive= (frame.args["כולל"]=="כן") | local inclusive = (frame.args["כולל"]=="כן") | ||
local success, res = pcall(parseDateRange, frame.args[1], diffFormat, inclusive) | local success, res = pcall(parseDateRange, frame.args[1], diffFormat, inclusive) | ||
if success then | if success then | ||
local str=res | local str=res | ||
-- the following translations are needed because the underline function | -- the following translations are needed because the underline function | ||
-- local format is wierd | -- local format is wierd | ||
str = mw.ustring.gsub(str, | str = mw.ustring.gsub(str, "(כ)־([א-ת])", "%1%2") | ||
if frame.args[2] == "גיל" then | if frame.args[2] == "גיל" then | ||
| שורה 740: | שורה 949: | ||
str = 1 | str = 1 | ||
end | end | ||
str = mw.ustring.gsub(str," שנה", "") | |||
if tonumber(str) > 0 and | if tonumber(str) > 0 and | ||
tonumber(parseDateRange(frame.args[1], "raw", inclusive)) < 0 then | tonumber(parseDateRange(frame.args[1], "raw", inclusive)) < 0 then | ||
| שורה 761: | שורה 971: | ||
dateType='D' | dateType='D' | ||
end | end | ||
local success, res = pcall( parseStrDate, frame.args[1], dateType ) | local success, res = pcall( parseStrDate, frame.args[1], dateType ) | ||
if success then | if success then | ||
| שורה 772: | שורה 982: | ||
end | end | ||
end | |||
function linkStrDateUnsafe(frame) | |||
local dateStr = frame.args[1] | |||
local linkedDateStr = dateStr | |||
-- Strip [ and ] chars | |||
linkedDateStr = mw.ustring.gsub(linkedDateStr, '%[', '') | |||
linkedDateStr = mw.ustring.gsub(linkedDateStr, '%]', '') | |||
-- Link D M Y, return [[D M]] [[Y]] | |||
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%d+ %a+) (%d+)$', '[[%1]] [[%2]]') | |||
-- Link D M, return [[D M]] | |||
if mw.ustring.find(linkedDateStr, '%[') == nil then | |||
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%d+) (%a+)$', '[[%1 %2]]') | |||
end | |||
-- Link M Y, return [[M]] [[Y]] | |||
if mw.ustring.find(linkedDateStr, '%[') == nil then | |||
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%a+) (%d+)$', '[[%1]] [[%2]]') | |||
end | |||
-- Link Y, return [[Y]] | |||
if mw.ustring.find(linkedDateStr, '%[') == nil then | |||
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%d+)$', '[[%1]]') | |||
end | |||
-- Unknown date string format, return the original string | |||
if mw.ustring.find(linkedDateStr, '%[') == nil then | |||
linkedDateStr = dateStr | |||
end | |||
return linkedDateStr | |||
end | end | ||
| שורה 777: | שורה 1,014: | ||
Date['חשב טווח'] = parseDateRangeSafe; | Date['חשב טווח'] = parseDateRangeSafe; | ||
Date['parseDateRange'] = parseDateRange; | Date['parseDateRange'] = parseDateRange; | ||
Date['מקושר'] = linkStrDateUnsafe; | |||
return Date | return Date | ||
גרסה אחרונה מ־20:14, 18 ביוני 2023
יחידה זו מיועדת לביצוע פעולות נפוצות על תאריכים.
- #חשב - מקבלת תאריך טקסטואלי ופורמט ומחלצת את מהתאריך את הפורמט הרצוי
- #חשב טווח - מקבלת טווח תאריכים ומחשבת את ההפרש ביניהם
חשב
[עריכת קוד מקור]| פורמט | דוגמה | תוצאה |
|---|---|---|
| יום | {{#invoke:תאריך|חשב|[[3 בפברואר]] [[2013]]|יום}} | 3 |
| יום | {{#invoke:תאריך|חשב|[[3 בפברואר]] [[2013]]{{הערה|א}}|יום}} | 3 |
| חודש | {{#invoke:תאריך|חשב|[[3 בפברואר]] [[2013]]|חודש}} | 2 |
| שנה | {{#invoke:תאריך|חשב|[[3 בפברואר]] [[2013]]|שנה}} | 2013 |
| שנה | {{#invoke:תאריך|חשב|[[פברואר]] [[2013]]|שנה}} | 2013 |
| TS | {{#invoke:תאריך|חשב|[[3 בפברואר]] [[2013]]|TS}} | 2013-02-03 |
הערות:
- פורמט TS ניתן להעביר לפונקציות זמן של הוראות תנאי.
- ההמרה מתעלמת מסוגריים מרובעות של קישורים
- ניתן להוסיף פרמטר error והתוכן שלו יוצג במקרה של שגיאה בתאריך. (רצוי להכניס במקרה כזה את הדף לקטגוריה כלשהי שתאפשר מעקב אחרי דפים לא תקינים. ברירת המחדל היא קטגוריה:דפים עם שגיאות בתאריך)
חשב טווח
[עריכת קוד מקור]| דוגמה | תוצאה | |
|---|---|---|
| פורמט ברירת מחדל: אוטומטי | {{#invoke:תאריך|חשב טווח|[[3 בפברואר]] [[1947]] - [[15 בספטמבר]] [[2013]]}} | 66 שנים |
| פורמט ברירת מחדל: אוטומטי (דוגמה עם שנים וסימן מינוס) | {{#invoke:תאריך|חשב טווח|1947 - 2013}} | כ־66 שנים |
| פורמט ברירת מחדל: אוטומטי (דוגמה עם שנים וסימן קו מפריד) | {{#invoke:תאריך|חשב טווח|1947–2013}} | כ־66 שנים |
| שנים | {{#invoke:תאריך|חשב טווח|[[3 בפברואר]] [[1947]] - [[15 בספטמבר]] [[2013]]|שנים}} | 66 שנים |
| גיל | {{#invoke:תאריך|חשב טווח|1 במרץ 1922 - 4 בנובמבר 1995|גיל}} | 73 |
| גיל | {{#invoke:תאריך|חשב טווח|1 במרץ 1922{{הערה|ב}} - 4 בנובמבר 1995|גיל}} | 73 |
| גיל | {{#invoke:תאריך|חשב טווח|1 במרץ 1994{{הערה|ב}} - 4 בנובמבר 1995|גיל}} | שנה |
| גיל | {{#invoke:תאריך|חשב טווח|1 במרץ 1993{{הערה|ב}} - 4 בנובמבר 1995|גיל}} | שנתיים |
| מספר | {{#invoke:תאריך|חשב טווח|1 במרץ 1922 - 4 בנובמבר 1995|מספר}} | 73 |
| מספר | {{#invoke:תאריך|חשב טווח|1 במרץ 1922{{הערה|ב}} - 4 בנובמבר 1995|מספר}} | 73 |
| מספר | {{#invoke:תאריך|חשב טווח|1 במרץ 1994{{הערה|ב}} - 4 בנובמבר 1995|מספר}} | 1 |
| מספר | {{#invoke:תאריך|חשב טווח|1 במרץ 1993{{הערה|ב}} - 4 בנובמבר 1995|מספר}} | 2 |
| שנים לפנה"ס | {{#invoke:תאריך|חשב טווח|[[3 בפברואר]] 1900 לפנה"ס - [[15 בספטמבר]] [[2013]]|שנים}} | 3,913 שנים |
| ימים | {{#invoke:תאריך|חשב טווח|[[3 בפברואר]] [[1947]] - [[15 בספטמבר]] [[2013]]|ימים}} | 24,331 ימים |
| הפרש | {{#invoke:תאריך|חשב טווח|[[3 בפברואר]] [[1947]] - [[15 בספטמבר]] [[2013]]|הפרש}} | 2102198400 |
| ללא תאריך יעד | {{#invoke:תאריך|חשב טווח|[[3 בפברואר]] [[1947]]|שנים}} | 79 שנים |
| לא כולל היום האחרון | {{#invoke:תאריך|חשב טווח|5 ביוני 1967 - 10 ביוני 1967}} | 5 ימים |
| כולל היום האחרון | {{#invoke:תאריך|חשב טווח|5 ביוני 1967 - 10 ביוני 1967|כולל=כן}} | 6 ימים |
| כולל היום האחרון | {{#invoke:תאריך|חשב טווח|14 ספטמבר 2014 - 14 ספטמבר 2014|כולל=כן}} | |
| שנה ויום | {{#invoke:תאריך|חשב טווח|14 ספטמבר 2014 - 15 ספטמבר 2015|כולל=כן}} | שנה |
הערות:
- כאשר לא ניתן תאריך יעד תאריך היעד נקבע כזמן הנוכחי
- הפרש - מציין את הפרש הזמנים בשניות וללא מילים. ניתן להשתמש בערך המוחזר בחלוקה מתאימה לקבלת יחידות זמן אחרות.
- ניתן להוסיף פרמטר כולל=כן, ואז נלקח בחשבון גם היום האחרון. כשמדובר על טווח זמן ארוך והפורמט נבחר אוטומטי או שמכיל שנים, מתקבלת תוצאה מקורבת.
- ניתן להוסיף פרמטר error והתוכן שלו יוצג במקרה של שגיאה בטווח התאריכים. (רצוי להכניס במקרה כזה את הדף לקטגוריה כלשהי שתאפשר מעקב אחרי דפים לא תקינים. ברירת המחדל היא קטגוריה:דפים עם שגיאות בתאריך)
- אם לא מצוין פורמט, הוא נבחר אוטומטית:
- עד ל-3 שבועות הוא מוצג בימים
- עד שנה הוא מוצג בימים ושבועות
- עד ל-10 שנים בשנים ושבועות
- מעבר לזה רק בשנים
בדיקות
[עריכת קוד מקור]דוגמאות לשימוש ביחידה ופלט לדוגמה מודגמים ביחידה:תאריך/בדיקות.
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
--offset
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("Calendars don't 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 = {'years', 'days'}
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
function linkStrDateUnsafe(frame)
local dateStr = frame.args[1]
local linkedDateStr = dateStr
-- Strip [ and ] chars
linkedDateStr = mw.ustring.gsub(linkedDateStr, '%[', '')
linkedDateStr = mw.ustring.gsub(linkedDateStr, '%]', '')
-- Link D M Y, return [[D M]] [[Y]]
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%d+ %a+) (%d+)$', '[[%1]] [[%2]]')
-- Link D M, return [[D M]]
if mw.ustring.find(linkedDateStr, '%[') == nil then
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%d+) (%a+)$', '[[%1 %2]]')
end
-- Link M Y, return [[M]] [[Y]]
if mw.ustring.find(linkedDateStr, '%[') == nil then
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%a+) (%d+)$', '[[%1]] [[%2]]')
end
-- Link Y, return [[Y]]
if mw.ustring.find(linkedDateStr, '%[') == nil then
linkedDateStr = mw.ustring.gsub(linkedDateStr, '^(%d+)$', '[[%1]]')
end
-- Unknown date string format, return the original string
if mw.ustring.find(linkedDateStr, '%[') == nil then
linkedDateStr = dateStr
end
return linkedDateStr
end
Date['חשב'] = parseStrDateSafe;
Date['חשב טווח'] = parseDateRangeSafe;
Date['parseDateRange'] = parseDateRange;
Date['מקושר'] = linkStrDateUnsafe;
return Date