Module:Citation/CS1/Date validation: Difference between revisions
Module:Citation/CS1/Date validation (view source)
Revision as of 15:52, 31 March 2024
, 31 March 2024julian date fix;
imported>Stuwisi m (1 revision imported) |
w>Trappist the monk (julian date fix;) |
||
Line 185: | Line 185: | ||
end | end | ||
year = tonumber (year) or lang_object:parseFormattedNumber (year); -- convert to number for the comparison; | year = tonumber (year) or lang_object:parseFormattedNumber (year); -- convert to number for the comparison | ||
if year and (100 > year) then -- years less than 100 not supported | |||
return false; | |||
end | |||
if 'pmc-embargo-date' == param then -- special case for |pmc-embargo-date= | if 'pmc-embargo-date' == param then -- special case for |pmc-embargo-date= | ||
Line 321: | Line 324: | ||
local date; -- one date or first date in a range | local date; -- one date or first date in a range | ||
local date2 = ''; -- end of range date | local date2 = ''; -- end of range date | ||
input.year = tonumber (input.year) or lang_object:parseFormattedNumber (input.year); -- language-aware tonumber() | |||
input.year2 = tonumber (input.year2) or lang_object:parseFormattedNumber (input.year2); -- COinS dates are pseudo-ISO 8601 so convert to Arabic numerals | |||
if ((1582 == input.year) and (10 > tonumber(input.month))) or (1582 > input.year) then -- if a Julian calendar date | |||
tCOinS_date.rftdate = tostring (input.year); -- &rft.date gets year only | |||
return; -- done | |||
end | end | ||
-- | -- here for all forms of Gregorian dates | ||
if 20 < tonumber (input.month) then -- if season, quarter, or proper-name date | |||
if | date = input.year; -- &rft.date gets year only | ||
date = input.year; | |||
if 0 ~= input.year2 and input.year ~= input.year2 then -- if a range, only the second year portion when not the same as range start year | if 0 ~= input.year2 and input.year ~= input.year2 then -- if a range, only the second year portion when not the same as range start year | ||
date = string.format ('%.4d/%.4d', | date = string.format ('%.4d/%.4d', input.year, input.year2) -- assemble the date range | ||
end | end | ||
local season = {[24] = 'winter', [21] = 'spring', [22] = 'summer', [23] = 'fall', [33] = '1', [34] = '2', [35] = '3', [36] = '4', [98] = 'Easter', [99] = 'Christmas'}; -- seasons lowercase, no autumn; proper-names use title case | |||
if 0 == input.month2 then -- single season, quarter, or proper-name date | |||
if 40 < tonumber(input.month) then | |||
tCOinS_date.rftchron = season[input.month]; -- proper-name date; used in journal metadata only | |||
elseif 30 < tonumber(input.month) then | |||
tCOinS_date.rftquarter = season[input.month]; -- quarter date; used in journal metadata only | |||
else | |||
tCOinS_date.rftssn = season[input.month]; -- season date; used in journal metadata only | |||
end | |||
else -- season ranges are lumped into &rft.chron; &rft.ssn and &rft.quarter are left blank | |||
if input.year ~= input.year2 then -- season year – season year range or season year–year | |||
if 0 ~= input.month2 then | |||
tCOinS_date.rftchron = string.format ('%s %s – %s %s', season[input.month], input.year, season[input.month2], input.year2); -- used in journal metadata only | |||
end | end | ||
else -- season–season year range | |||
tCOinS_date.rftchron = season[input.month] .. '–' .. season[input.month2]; -- season–season year range; used in journal metadata only | |||
end | end | ||
end | end | ||
tCOinS_date.rftdate = date; | |||
tCOinS_date.rftdate = tostring (date); | |||
return; -- done | return; -- done | ||
end | end | ||
-- here for gregorian calendar dates | |||
if 0 ~= input.day then | if 0 ~= input.day then | ||
date = string.format ('%s-%.2d-%.2d', input.year, tonumber(input.month), tonumber(input.day)); -- whole date | date = string.format ('%s-%.2d-%.2d', input.year, tonumber(input.month), tonumber(input.day)); -- whole date | ||
Line 621: | Line 618: | ||
year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns['y4-y2'][1]); | year, century, anchor_year, year2 = mw.ustring.match(date_string, patterns['y4-y2'][1]); | ||
anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years | anchor_year = year .. '–' .. anchor_year; -- assemble anchor year from both years | ||
if 13 > tonumber(year2) then return false; end -- don't allow 2003-05 which might be May 2003 | if 13 > tonumber(year2) then return false; end -- don't allow 2003-05 which might be May 2003 | ||
year2 = century .. year2; | year2 = century .. year2; -- add the century to year2 for comparisons | ||
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same | if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same | ||
if not is_valid_year(year2) then return false; end -- no year farther in the future than next year | if not is_valid_year(year2) then return false; end -- no year farther in the future than next year | ||
if in_array (param, {'date', 'publication-date', 'year'}) then -- here when 'valid' abbreviated year range; if one of these parameters | |||
add_prop_cat ('year-range-abbreviated'); -- add properties cat | |||
end | |||
elseif mw.ustring.match(date_string, patterns['y'][1]) then -- year; here accept either YYY or YYYY | elseif mw.ustring.match(date_string, patterns['y'][1]) then -- year; here accept either YYY or YYYY | ||
Line 641: | Line 638: | ||
end | end | ||
if 'access-date' == param then -- test | if param ~= 'date' then -- CITEREF disambiguation only allowed in |date=; |year= & |publication-date= promote to date | ||
if anchor_year:match ('%l$') then | |||
return false; | |||
end | |||
end | |||
if 'access-date' == param then -- test access-date here because we have numerical date parts | |||
if 0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required | if 0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required | ||
0 == year2 and 0 == month2 and 0 == day2 then -- none of these; | 0 == year2 and 0 == month2 and 0 == day2 then -- none of these; access-date must not be a range | ||
if not is_valid_accessdate(year .. '-' .. month .. '-' .. day) then | if not is_valid_accessdate(year .. '-' .. month .. '-' .. day) then | ||
return false; -- return false when | return false; -- return false when access-date out of bounds | ||
end | end | ||
else | else | ||
return false; -- return false when | return false; -- return false when access-date is a range of two dates | ||
end | |||
end | |||
if 'archive-date' == param then -- test archive-date here because we have numerical date parts | |||
if not (0 ~= year and 0 ~= month and 0 ~= day and -- all parts of a single date required | |||
0 == year2 and 0 == month2 and 0 == day2) then -- none of these; archive-date must not be a range | |||
return false; -- return false when archive-date is a range of two dates | |||
end | end | ||
end | end | ||
Line 1,025: | Line 1,035: | ||
date_parameters_list[param_name].val = new_date; -- update date in date list | date_parameters_list[param_name].val = new_date; -- update date in date list | ||
result = true; -- and announce that changes have been made | result = true; -- and announce that changes have been made | ||
break; | |||
end | end | ||
end -- if | end -- if | ||
Line 1,102: | Line 1,113: | ||
xlate = is_xlateable (month); -- get translate <month>; returns translation or nil | xlate = is_xlateable (month); -- get translate <month>; returns translation or nil | ||
if xlate then | if xlate then | ||
date = mw.ustring.gsub (date, month, xlate); -- replace the English with the translation | date = mw.ustring.gsub (date, month, xlate); -- replace the English with the translation | ||
date_parameters_list[param_name].val = date; -- save the translated date | date_parameters_list[param_name].val = date; -- save the translated date | ||
Line 1,165: | Line 1,147: | ||
cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration | cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration | ||
end | |||
--[[--------------------------< A R C H I V E _ D A T E _ C H E C K >------------------------------------------ | |||
Compare value in |archive-date= with the timestamp in Wayback machine urls. Emits an error message with suggested | |||
date from the |archive-url= timestamp in an appropriate format when the value in |archive-date= does not match | |||
the timestamp. | |||
this function never called when any date in a cs1|2 template has errors | |||
error message suggests new |archive-date= value in an appropriate format specified by <df>. <df> is either | |||
|df= or cfg.global_df in that order. If <df> is nil, suggested date has format from |archive-date=. There is | |||
a caveat: when |df=dmy or |df=mdy, the reformatter leaves |access-date= and |archive-date= formats as they are. | |||
The error message suggested date is passed to the formatter as YYYY-MM-DD so when |df=dmy or |df=mdy, the format | |||
is not changed. | |||
]] | |||
local function archive_date_check (archive_date, archive_url_timestamp, df) | |||
local archive_date_format = 'dmy-y'; -- holds the date format of date in |archive-date; default to ymd; 'dmy' used here to spoof reformat_dates() | |||
for _, v_t in ipairs ({{'dMy', 'dmy-all'}, {'Mdy', 'mdy-all'}}) do -- is |archive-date= format dmy or mdy? | |||
if archive_date:match (patterns[v_t[1]][1]) then -- does the pattern match? | |||
archive_date_format = cfg.keywords_xlate[v_t[2]]; -- get appropriate |df= supported keyword from the i18n translator table | |||
break; | |||
end | |||
end | |||
local dates_t = {}; | |||
dates_t['archive-date'] = {val=archive_date, name=''}; -- setup to call reformat_dates(); never called when errors so <name> unset as not needed | |||
reformat_dates (dates_t, 'dmy-y'); -- reformat |archive-date= to ymd; 'dmy' used here to spoof reformat_dates() | |||
local archive_url_date = archive_url_timestamp:gsub ('(%d%d%d%d)(%d%d)(%d%d)%d*', '%1-%2-%3'); -- make ymd format date from timestamp | |||
if dates_t['archive-date'].val == archive_url_date then -- are the two dates the same | |||
return; -- yes, done | |||
else | |||
dates_t['archive-date'] = {val=archive_url_date, name=''}; -- setup to call reformat_dates() with the timestamp date | |||
reformat_dates (dates_t, df or archive_date_format); -- reformat timestamp to format specified by <df> or format used in |archive-date= | |||
archive_url_date = dates_t['archive-date'].val; | |||
set_message ('err_archive_date_url_ts_mismatch', archive_url_date); -- emit an error message | |||
end | |||
end | end | ||
Line 1,172: | Line 1,196: | ||
return { -- return exported functions | return { -- return exported functions | ||
archive_date_check = archive_date_check, | |||
date_hyphen_to_dash = date_hyphen_to_dash, | |||
date_name_xlate = date_name_xlate, | |||
dates = dates, | dates = dates, | ||
reformat_dates = reformat_dates, | |||
set_selected_modules = set_selected_modules, | |||
year_date_check = year_date_check, | year_date_check = year_date_check, | ||
} | } |