Modul:Wikidata/Formatters/time
Vzhled
require "Modul:No globals"
local p = {}
local lib = require 'Modul:Wikidata/lib'
local i18n = mw.loadData("Modul:Wikidata/i18n")
local function getPrecision(timevalue, opt_precision)
return math.min(timevalue.precision, opt_precision or 15)
end
local function okPrecision(timevalue, opt_precision, target_precision)
if timevalue == 'somevalue' or timevalue == 'novalue' then
return target_precision < 10
end
return target_precision == getPrecision(timevalue, opt_precision)
end
function p.yearDifference(sooner, later)
local age = later.year - sooner.year
--[[ pravděpodobně chybně, prozatím skryto
if age % 4 == 0 and (age % 100 ~= 0 or age % 400 == 0) then
age = math.floor(age/4)
end
]]--
if sooner.precision > 10 then
if later.precision > 10 then
if sooner.month > later.month then
age = age - 1
elseif sooner.month == later.month and sooner.day > later.day then
age = age - 1
end
return age, age
elseif later.precision == 10 then
if sooner.month == later.month then
return age - 1, age - 1 .. '–' .. age
end
if sooner.month > later.month then
age = age - 1
end
return age, age
end
elseif sooner.precision == 10 then
if later.precision > 9 then
if sooner.month == later.month then
return age - 1, age - 1 .. '–' .. age
end
if sooner.month > later.month then
age = age - 1
end
return age, age
end
end
return age - 1, age - 1 .. '–' .. age
end
--[[
local function julGregDifference(timevalue)
-- todo: Lua
return tonumber(mw.getCurrentFrame():expandTemplate{
title = 'JULGREGDATUM/AnzahlTage',
args = { timevalue.month, timevalue.year }
})
end
]]
function p.julianToGregorian(timevalue)
-- https://en.wikipedia.org/wiki/Gregorian_calendar#Difference_between_Gregorian_and_Julian_calendar_dates
local year = timevalue.year
local diff = math.floor(year / 100) - math.floor(year / 400) - 2
if year % 100 == 0 and year % 400 ~= 0 then
if timevalue.month == 2 and 30 - timevalue.day > diff then
diff = diff - 1
end
end
local feb_days
if year % 4 == 0 then
feb_days = 29
else
feb_days = 28
end
local days = { 31, feb_days, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
local newvalue = mw.clone(timevalue)
newvalue.calendar = newvalue.CALENDAR.GREGORIAN
newvalue.day = newvalue.day + diff
if newvalue.day > days[newvalue.month] then
newvalue.day = newvalue.day - days[newvalue.month]
newvalue.month = newvalue.month + 1
if newvalue.month > 12 then
newvalue.month = 1
newvalue.year = newvalue.year + 1
end
end
return newvalue
end
local function stripZero(date, lang, timevalue)
-- odstraň nuly na začátku (rok < 1000 a > -1000)
local year
if timevalue.year > 0 then
year = math.abs(timevalue.year)
else
year = math.abs(timevalue.year) - 1
end
return mw.ustring.gsub(
date,
lang:formatNum(0) .. '+(' .. lang:formatNum(year, { noCommafy = true }) .. ')',
'%1'
)
end
function p.formatTimevalue(timevalue, options)
local lang = mw.getContentLanguage()
local precision = getPrecision(timevalue, options.precision)
local timestring = tostring(timevalue)
local linked_app = ''
if not lib.IsOptionTrue(options, 'nolink') then
linked_app = '-linked'
end
local BCE_app = ''
if timevalue.year < 0 then
timestring = mw.ustring.sub(timestring, 2)
BCE_app = '-BCE'
end
local newstring
if precision > 8 then
local key = ({ [9] = 'year', [10] = 'year-month', [11] = 'year-month-day' })[math.min(precision, 11)] .. BCE_app
local pattern = i18n.date[key .. linked_app] or i18n.date[key]
if precision > 10 and timevalue.calendar == timevalue.CALENDAR.JULIAN and timevalue > timevalue.newFromIso8601( '1582-10-04' ) then
local newvalue = p.julianToGregorian(timevalue)
local jul_pattern
if newvalue.year ~= timevalue.year then
jul_pattern = i18n.date['year-month-day']
elseif newvalue.month ~= timevalue.month then
jul_pattern = i18n.date['month-day']
else
jul_pattern = i18n.date.day
end
if newvalue.month == 2 and newvalue.day == 29 then
if year % 100 == 0 and year % 400 ~= 0 then
timevalue.year = 2000 -- hack to force formatting 29th February
end
end
newstring = mw.ustring.format('%s%s / %s%s',
stripZero(lang:formatDate(jul_pattern, timestring), lang, timevalue),
i18n.date.julian,
stripZero(lang:formatDate(pattern, tostring(newvalue)), lang, newvalue),
i18n.date.gregorian)
else
newstring = stripZero(lang:formatDate(pattern, timestring), lang, timevalue)
end
elseif precision > 5 then
local key = ({ [6] = 'millenium', [7] = 'century', [8] = 'decade' })[precision] .. BCE_app
local coef = 10 ^ (9 - precision)
local number = math.floor(math.abs(timevalue.year) / coef)
if precision == 8 then
number = number * coef
end
newstring = mw.getCurrentFrame():preprocess(
mw.message.newRawMessage(i18n.date[key .. linked_app] or i18n.date[key])
:params(lang:formatNum(number, { noCommafy = true }))
:plain()
)
else
-- TODO
newstring = timestring
end
return newstring
end
p.formatDateFromTimevalue = p.formatTimevalue
local function formatDateOrSpecial(timevalue, options)
if timevalue == 'somevalue' then
return '?'
else
return p.formatTimevalue(timevalue, options)
end
end
function p.formatDateRange(dates, options)
if not (dates.begin or dates.ending) then
return error()
end
if not dates.begin then
return mw.ustring.format(i18n.date['end'], formatDateOrSpecial(dates.ending, options))
end
if not dates.ending then
return mw.ustring.format(i18n.date['start'], formatDateOrSpecial(dates.begin, options))
end
local begin = formatDateOrSpecial(dates.begin, options)
local ending = formatDateOrSpecial(dates.ending, options)
if begin == ending then
return begin
end
local connector = ' – '
if okPrecision(dates.begin, options.precision, 9) and okPrecision(dates.ending, options.precision, 9) then
connector = '–'
end
return table.concat( { begin, ending }, connector )
end
-- @deprecated
function p.AreDatesSame(first, second, strict)
return first == second
end
function p.getRawValue(value, options)
local Time = require 'Modul:Time'
return Time.newFromWikidataValue(value)
end
function p.formatValue(value, options)
local timevalue = p.getRawValue(value, options)
local formatted = p.formatTimevalue(timevalue, options)
if lib.IsOptionTrue(options, 'birthdate') and timevalue.precision > 8 then
if #options.entity:getBestStatements('P570') == 0 then
local Time = require 'Modul:Time'
local age, age_text = p.yearDifference(timevalue, Time.new(os.date('!*t')))
formatted = mw.ustring.format('%s (%s)', formatted,
mw.getCurrentFrame():preprocess(
mw.message.newRawMessage(i18n.date.age)
:params(age_text)
:numParams(age)
:plain()
)
)
if age >= 100 then
formatted = formatted .. lib.category('centenarians-living')
elseif age < 0 then
formatted = formatted .. lib.category('failed-age-computing')
end
end
elseif lib.IsOptionTrue(options, 'deathdate') and timevalue.precision > 8 then
local birthvalue
for _, statement in ipairs(options.entity:getBestStatements('P569')) do
if lib.IsSnakValue(statement.mainsnak) then
local Formatters = require 'Modul:Wikidata/Formatters'
birthvalue = Formatters.getRawValue(statement.mainsnak)
break
end
end
if birthvalue and birthvalue.precision > 8 then
local age, age_text = p.yearDifference(birthvalue, timevalue)
formatted = mw.ustring.format('%s (%s)', formatted,
mw.getCurrentFrame():preprocess(
mw.message.newRawMessage(i18n.date['in-the-age'])
:params(age_text)
:numParams(age)
:plain()
)
)
if age >= 100 then
formatted = formatted .. lib.category('centenarians')
end
end
end
return formatted
end
p.formatRawValue = p.formatTimevalue
return p