Module:Citation/CS1/Date validation: Difference between revisions
Synch from sandbox;
m>Trappist the monk (Synch from sandbox;) |
m>Trappist the monk (Synch from sandbox;) |
||
Line 97: | Line 97: | ||
return true; | return true; | ||
end | end | ||
--[[--------------------------< I S _ V A L I D _ Y E A R >---------------------------------------------------- | --[[--------------------------< I S _ V A L I D _ Y E A R >---------------------------------------------------- | ||
Line 112: | Line 111: | ||
end | end | ||
--[[ | --[[--------------------------< I S _ V A L I D _ D A T E >---------------------------------------------------- | ||
Returns true if day is less than or equal to the number of days in month and year is no farther into the future than next year; else returns false. | Returns true if day is less than or equal to the number of days in month and year is no farther into the future | ||
than next year; else returns false. | |||
Assumes Julian calendar prior to year 1582 and Gregorian calendar thereafter. Accounts for Julian calendar leap | |||
years before 1582 and Gregorian leap years after 1582. Where the two calendars overlap (1582 to approximately | |||
1923) dates are assumed to be Gregorian. | |||
]] | ]] | ||
local function is_valid_date (year, month, day) | local function is_valid_date (year, month, day) | ||
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
local month_length; | local month_length; | ||
if not is_valid_year(year) then -- no farther into the future than next year | if not is_valid_year(year) then -- no farther into the future than next year | ||
return false; | return false; | ||
end | end | ||
if (2==month) then | month = tonumber(month); -- required for YYYY-MM-DD dates | ||
month_length = 28; | |||
if 1582 > tonumber(year) then | if (2==month) then -- if February | ||
month_length = 28; -- then 28 days unless | |||
if 1582 > tonumber(year) then -- Julian calendar | |||
if 0==(year%4) then | if 0==(year%4) then | ||
month_length = 29; | month_length = 29; | ||
end | end | ||
else | else -- Gregorian calendar | ||
if (0==(year%4) and (0~=(year%100) or 0==(year%400))) then -- is a leap year? | if (0==(year%4) and (0~=(year%100) or 0==(year%400))) then -- is a leap year? | ||
month_length = 29; | month_length = 29; -- if leap year then 29 days in February | ||
end | end | ||
end | end | ||
else | else | ||
month_length=days_in_month[ | month_length=days_in_month[month]; | ||
end | end | ||
Line 213: | Line 218: | ||
This function receives a table of date parts for one or two dates and an empty table reference declared in | This function receives a table of date parts for one or two dates and an empty table reference declared in | ||
Module:Citation/CS1. The function is called only for |date= parameters and only if the |date=<value> is | Module:Citation/CS1. The function is called only for |date= parameters and only if the |date=<value> is | ||
determined to be a valid date format. The question of what to do with | determined to be a valid date format. The question of what to do with invalid date formats is not answered here. | ||
The date parts in the input table are converted to an ISO 8601 conforming date string: | The date parts in the input table are converted to an ISO 8601 conforming date string: | ||
Line 296: | Line 301: | ||
--[[--------------------------< C H E C K _ D A T E >---------------------------------------------------------- | --[[--------------------------< C H E C K _ D A T E >---------------------------------------------------------- | ||
Check date format to see that it is one of the formats approved by WP:DATESNO or WP:DATERANGE. Exception: only allowed range separator is endash. | Check date format to see that it is one of the formats approved by WP:DATESNO or WP:DATERANGE. Exception: only | ||
Additionally, check the date to see that it is a real date: no 31 in 30-day months; no 29 February when not a leap year. Months, both long-form and three | allowed range separator is endash. Additionally, check the date to see that it is a real date: no 31 in 30-day | ||
character abbreviations, and seasons must be spelled correctly. Future years beyond next year are not allowed. | months; no 29 February when not a leap year. Months, both long-form and three character abbreviations, and seasons | ||
must be spelled correctly. Future years beyond next year are not allowed. | |||
If the date fails the format tests, this function returns false and does not return values for anchor_year and COinS_date. When this happens, the date parameter is | If the date fails the format tests, this function returns false and does not return values for anchor_year and | ||
used in the COinS metadata and the CITEREF identifier gets its year from the year parameter if present otherwise CITEREF does not get a date value. | COinS_date. When this happens, the date parameter is used in the COinS metadata and the CITEREF identifier gets | ||
its year from the year parameter if present otherwise CITEREF does not get a date value. | |||
Inputs: | Inputs: | ||
Line 310: | Line 317: | ||
true, anchor_year, COinS_date | true, anchor_year, COinS_date | ||
anchor_year can be used in CITEREF anchors | anchor_year can be used in CITEREF anchors | ||
COinS_date is ISO 8601 format date; see make_COInS_date() | COinS_date is ISO 8601 format date; see make_COInS_date() | ||
]] | ]] | ||
local function check_date (date_string, tCOinS_date) | local function check_date (date_string, tCOinS_date) | ||
local year; -- assume that year2, months, and days are not used; | local year; -- assume that year2, months, and days are not used; | ||
Line 415: | Line 423: | ||
end | end | ||
elseif date_string:match ("^%a+–%a+ +[1-9]%d%d%d%a?$") then | elseif date_string:match ("^%a+–%a+ +[1-9]%d%d%d%a?$") then -- month/season range year; months separated by endash | ||
month, month2, anchor_year, year=date_string:match ("(%a+)–(%a+)%s*((%d%d%d%d)%a?)"); | month, month2, anchor_year, year=date_string:match ("(%a+)–(%a+)%s*((%d%d%d%d)%a?)"); | ||
if (not is_valid_month_season_range(month, month2)) or (not is_valid_year(year)) then return false; end | if (not is_valid_month_season_range(month, month2)) or (not is_valid_year(year)) then return false; end | ||
Line 461: | Line 469: | ||
else | else | ||
return false; | return false; -- date format not one of the MOS:DATE approved formats | ||
end | end | ||
local result=true; | local result=true; -- check whole dates for validity; assume true because not all dates will go through this test | ||
if 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 == day2 then -- YMD (simple whole date) | if 0 ~= year and 0 ~= month and 0 ~= day and 0 == year2 and 0 == month2 and 0 == day2 then -- YMD (simple whole date) | ||
result=is_valid_date(year,month,day); | result=is_valid_date(year,month,day); | ||
Line 482: | Line 490: | ||
if false == result then return false; end | if false == result then return false; end | ||
if nil ~= tCOinS_date then -- this table only passed into this function when testing |date= parameter values | if nil ~= tCOinS_date then -- this table only passed into this function when testing |date= parameter values | ||
Line 490: | Line 495: | ||
end | end | ||
return true, anchor_year; | return true, anchor_year; -- format is good and date string represents a real date | ||
end | end | ||
--[[--------------------------< D A T E S >-------------------------------------------------------------------- | --[[--------------------------< D A T E S >-------------------------------------------------------------------- | ||
Line 509: | Line 514: | ||
local COinS_date; -- will return as nil if the date being tested is not |date= | local COinS_date; -- will return as nil if the date being tested is not |date= | ||
local error_message = ""; | local error_message = ""; | ||
local good_date = false; | local good_date = false; | ||
for k, v in pairs(date_parameters_list) do | for k, v in pairs(date_parameters_list) do -- for each date-holding parameter in the list | ||
if is_set(v) then | if is_set(v) then -- if the parameter has a value | ||
if v:match("^c%. [1-9]%d%d%d?%a?$") then | if v:match("^c%. [1-9]%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year= | ||
local year = v:match("c%. ([1-9]%d%d%d?)%a?"); | local year = v:match("c%. ([1-9]%d%d%d?)%a?"); -- get the year portion so it can be tested | ||
if 'date'==k then | if 'date'==k then | ||
anchor_year, COinS_date = v:match("((c%. [1-9]%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter | anchor_year, COinS_date = v:match("((c%. [1-9]%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter | ||
Line 522: | Line 526: | ||
good_date = is_valid_year(year); | good_date = is_valid_year(year); | ||
end | end | ||
elseif 'date'==k then | elseif 'date'==k then -- if the parameter is |date= | ||
if v:match("^n%.d%.%a?") then | if v:match("^n%.d%.%a?") then -- if |date=n.d. with or without a CITEREF disambiguator | ||
good_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)"); --"n.d."; no error when date parameter is set to no date | good_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)"); --"n.d."; no error when date parameter is set to no date | ||
elseif v:match("^nd%a?$") then | elseif v:match("^nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator | ||
good_date, anchor_year, COinS_date = true, v:match("((nd)%a?)"); --"nd"; no error when date parameter is set to no date | good_date, anchor_year, COinS_date = true, v:match("((nd)%a?)"); --"nd"; no error when date parameter is set to no date | ||
else | else | ||
good_date, anchor_year, COinS_date = check_date (v, tCOinS_date); | good_date, anchor_year, COinS_date = check_date (v, tCOinS_date); -- go test the date | ||
end | end | ||
elseif 'access-date'==k then | elseif 'access-date'==k then -- if the parameter is |date= | ||
good_date = check_date (v); | good_date = check_date (v); -- go test the date | ||
if true == good_date then | if true == good_date then -- if the date is a valid date | ||
good_date = is_valid_accessdate (v); | good_date = is_valid_accessdate (v); -- is Wikipedia start date < accessdate < tomorrow's date? | ||
end | end | ||
else | else -- any other date-holding parameter | ||
good_date = check_date (v); | good_date = check_date (v); -- go test the date | ||
end | end | ||
if false==good_date then | if false==good_date then -- assemble one error message so we don't add the tracking category multiple times | ||
if is_set(error_message) then | if is_set(error_message) then -- once we've added the first portion of the error message ... | ||
error_message=error_message .. ", "; | error_message=error_message .. ", "; -- ... add a comma space separator | ||
end | end | ||
error_message=error_message .. "|" .. k .. "="; | error_message=error_message .. "|" .. k .. "="; -- add the failed parameter | ||
end | end | ||
end | end | ||
end | end | ||
return anchor_year, error_message; -- and done | return anchor_year, error_message; -- and done | ||
end | end | ||
--[[--------------------------< Y E A R _ D A T E _ C H E C K >------------------------------------------------ | --[[--------------------------< Y E A R _ D A T E _ C H E C K >------------------------------------------------ |