10,312
次編輯
變更
無編輯摘要
local p = {}
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------]] local is_set, in_array; -- imported functions from selected Module:Citation/CS1/Utilitieslocal cfg; -- table of tables imported from slected Module:Citation/CS1/Configuration --[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >----------------------------------------
returns true if:
adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow
local function is_valid_accessdate (accessdate)
local access_ts, tomorrow_ts; -- to hold unix time stamps representing the dates
accessdate = accessdate:gsub("年", "-");
accessdate = accessdate:gsub("月", "-");
accessdate = accessdate:gsub("日", "-");
accessdate = accessdate:gsub("-$", "");
good1, access_ts = pcall( lang.formatDate, lang, 'U', accessdate ); -- convert accessdate value to unix timesatmp
good2, tomorrow_ts = pcall( lang.formatDate, lang, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow
if good1 and good2 then -- lang.formatDate() returns a timestamp in the local script which which tonumber() may not understand access_ts = tonumber (access_ts) or lang:parseFormattedNumber (access_ts); -- convert to numbers for the comparison; tomorrow_ts = tonumber (tomorrow_ts) or lang:parseFormattedNumber (tomorrow_ts);
else
return false; -- one or both failed to convert to unix time stamp
end
if 979516800 <= access_ts and access_ts < tomorrow_ts then -- Wikipedia start date <= accessdate < tomorrow's date
return true;
end
end
--[[--------------------------< G E T _ M O N T H _ N U M B E R >----------------------------------------------
local function get_month_number (month)
end
--[[--------------------------< G E T _ S E A S O N _ N U M B E R >--------------------------------------------
returns a number according to the sequence of seasons in a year: 1 for Winter, etc. Capitalization and spelling must be correct. If not a valid season, returns 0
]]
local function get_season_number (season)
end
local function is_proper_name (name)
end
]]
local function is_valid_year(year)
if not is_set(year_limit) then
Month pairs are expected to be left to right, earliest to latest in time.
]]
local function is_valid_month_season_range(range_start, range_end)
local range_start_number = get_month_number (range_start);
if 0 == range_start_number then -- is this a month range?
local range_start_number = get_season_number (range_start); -- not a month; is it a season? get start season number local range_end_number = get_season_number (range_end); -- get end season number
if (0 ~= range_start_number) and (0 ~= then -- is start of range a season? if range_start_number < range_end_number) then -- range_start is a season return true; -- return truewhen range_end is also a season and follows start season; else false end if 24 == range_start_number and 21 == range_end_number then -- any special case when season pairing range is acceptedFall-Winter or Autumn-Winter return true; end
end
return false; -- range_start is not a month or a season; or range_start is a season and/or range_end is not a ; or improper seasonsequence
end
if range_start_number < range_end_number then -- range_start is a month; does range_start precede range_end?
if is_valid_month_range_style (range_start, range_end) then -- do months have the same style?
The input table has:
year, year2 – always present; if before 1582, ignore months and days if present
month, month2 – 0 if not provided, 1-12 for months, 21-24 for seasons; 99 Christmas31– proper name dates
day, day2 – 0 if not provided, 1-31 for days
local date; -- one date or first date in a range
local date2 = ''; -- end of range date
if 1582 > tonumber(input.year) or 20 < tonumber(input.month) then -- Julian calendar or season so &rft.date gets year only
end
if 20 < tonumber(input.month) then -- if season or propername date
local season = {[2421]='winter', [2122]='spring', [2223]='summer', [2324]='fall', [9931]='Christmas'}; -- seasons lowercase, no autumn; proper names use title case
if 0 == input.month2 then -- single season date
if 30 <tonumber(input.month) then
if input.year ~= input.year2 then -- season year – season year range or season year–year
tCOinS_date.rftssn = season[input.month]; -- start of range season; keep this?
if 0~= input.month2 then
tCOinS_date.rftchron = string.format ('%s %s – %s %s', season[input.month], input.year, season[input.month2], input.year2);
end
]]
local function check_date (date_string, tCOinS_date, test_accessdate)
local year; -- assume that year2, months, and days are not used;
local year2=0; -- second year in a year range
if date_string:match("^%d%d%d%d%-%d%d%-%d%d$") then -- year-initial numerical year month day format
year, month, day=string.match(date_string, "(%d%d%d%d)%-(%d%d)%-(%d%d)");
if 12 < tonumber(month) or 1 > tonumber(month) or 1582 1583 > tonumber(year) or 0 == tonumber(day) then return false; end -- month or day number not valid or not Gregorian calendar
anchor_year = year;
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial: month day, year month, day, anchor_year, year=mw.ustringstring.match(date_string, "(%D-a+) +%s*(%d%d?),%s*((%d%d%d%d?)%a?)");
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +[1-9]%d?[%- –][1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial day range: month day–day, year; days are separated by endash month, day, day2, anchor_year, year=mw.ustringstring.match(date_string, "(%D-a+) +(%d%d?)[%- –](%d%d?), +((%d%d%d%d)%a?)");
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
year2=year;
elseif mw.ustring.date_string:match(date_string, "^[1-9]%d? +%D- a+ +[1-9]%d%d%d%a?$") then -- day-initial: day month year day, month, anchor_year, year=mw.ustringstring.match(date_string, "(%d%d*)%s*(%D-a+) +%s*((%d%d%d%d?)%a?)");
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
elseif mw.ustring.date_string:match(date_string, "^[1-9]%d?[%- –][1-9]%d? +%D- a+ +[1-9]%d%d%d%a?$") then -- day-range-initial: day–day month year; days are separated by endash day, day2, month, anchor_year, year=mw.ustringstring.match(date_string, "(%d%d?)[%- –](%d%d?) +(%D-a+) +((%d%d%d%d)%a?)");
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
year2=year;
elseif mw.ustring.date_string:match(date_string, "^[1-9]%d? +%D- a+[%- –] +[1-9]%d? +%D- a+ +[1-9]%d%d%d%a?$") then -- day initial month-day-range: day month - day month year; uses spaced endash day, month, day2, month2, anchor_year, year=mw.ustring.date_string:match(date_string, "(%d%d?) +(%D-a+) +[%- –] +(%d%d?) +(%D-a+) +((%d%d%d%d)%a?)");
if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end -- date range order is left to right: earlier to later;
month = get_month_number (month); -- for metadata
year2=year;
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +[1-9]%d? +[– %-–] a+%D- +[1-9]%d?, +[1-9]%d%d%d?%a?$") then -- month initial month-day-range: month day – month day, year; uses spaced endash month, day, month2, day2, anchor_year, year=mw.ustring.date_string:match(date_string, "(%D-a+) +(%d%d?) +[%- –] +(%D-a+) +(%d%d?), +((%d%d%d%d)%a?)");
if (not is_valid_month_season_range(month, month2)) or not is_valid_year(year) then return false; end
month = get_month_number (month); -- for metadata
year2=year;
elseif mw.ustring.date_string:match(date_string, "^[1-9]%d? +%D- a+ +[1-9]%d%d%d +[%- –] +[1-9]%d? +%D- a+ +[1-9]%d%d%d%a?$") then -- day initial month-day-year-range: day month year - day month year; uses spaced endash day, month, year, day2, month2, anchor_year, year2=mw.ustring.date_string:match(date_string, "(%d%d?) +(%D-a+) +(%d%d%d%d?) +[%- –] +(%d%d?) +(%D-a+) +((%d%d%d%d?)%a?)");
if tonumber(year2) <= tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) or not is_valid_month_range_style(month, month2) then return false; end -- year2 no more than one year in the future; months same style
month2 = get_month_number (month2);
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +[1-9]%d?, +[1-9]%d%d%d +[– %-–] a+%D- +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month initial month-day-year-range: month day, year – month day, year; uses spaced endash month, day, year, month2, day2, anchor_year, year2=mw.ustring.date_string:match(date_string, "(%D-a+) +(%d%d?), +(%d%d%d%d) +[%- –] +(%D-a+) +(%d%d?), +((%d%d%d%d)%a?)");
if tonumber(year2) <= tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later
if not is_valid_year(year2) or not is_valid_month_range_style(month, month2) then return false; end -- year2 no more than one year in the future; months same style
month2 = get_month_number (month2);
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +[1-9]%d%d%d[%- –]%d%d%a?$") then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash
local century;
month, year, century, anchor_year, year2=mw.ustring.date_string:match(date_string, "(%D-a+) +((%d%d)%d%d)[%- –]((%d%d)%a?)");
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year=year..'–'..anchor_year; -- assemble anchor_year from both years
month = get_season_number (month);
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +[1-9]%d%d%d[%- –][1-9]%d%d%d%a?$") then -- special case Winter/Summer year-year; year separated with unspaced endash month, year, anchor_year, year2=mw.ustring.date_string:match(date_string, "(%D-a+) +(%d%d%d%d)[%- –]((%d%d%d%d)%a?)");
if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
anchor_year=year..'–'..anchor_year; -- assemble anchor_year from both years
month = get_season_number (month); -- for metadata
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +[1-9]%d%d%d +[%- –] %a+%D- +[1-9]%d%d%d%a?$") then -- month/season year - month/season year; separated by spaced endash month, year, month2, anchor_year, year2=mw.ustring.date_string:match(date_string, "(%D-a+) +(%d%d%d%d) +[%- –] +(%D-a+) +((%d%d%d%d)%a?)");
anchor_year=year..'–'..anchor_year; -- assemble anchor_year from both years
if tonumber(year) >= tonumber(year2) then return false; end -- left to right, earlier to later, not the same
end
elseif mw.ustring.date_string:match(date_string, "^%D-[%- a+ –]%D- a+ +[1-9]%d%d%d%a?$") then -- month/season range year; months separated by endash month, month2, anchor_year, year=mw.ustring.date_string:match(date_string, "(%D-a+)[%- –](%D-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 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season
year2=year;
elseif mw.ustring.date_string:match(date_string, "^%D- a+ +%d%d%d%d%a?$") then -- month/season year or proper-name year month, anchor_year, year=mw.ustring.date_string:match(date_string, "(%D-a+)%s*((%d%d%d%d)%a?)");
if not is_valid_year(year) then return false; end
if not is_valid_month_or_season (month) and 0 == is_proper_name (month) then return false; end
end
elseif mw.ustring.date_string:match(date_string, "^[1-9]%d%d%d?[%- –][1-9]%d%d%d?%a?$") then -- Year range: YYY-YYY or YYY-YYYY or YYYY–YYYY; separated by unspaced endash; 100-9999 year, anchor_year, year2=mw.ustring.date_string:match(date_string, "(%d%d%d%d?)[%- –]((%d%d%d%d?)%a?)");
anchor_year=year..'–'..anchor_year; -- assemble anchor year from both years
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
elseif mw.ustring.date_string:match(date_string, "^[1-9]%d%d%d[%- –]%d%d%a?$") then -- Year range: YYYY–YY; separated by unspaced endash
local century;
year, century, anchor_year, year2=mw.ustring.date_string:match(date_string, "((%d%d)%d%d)[%- –]((%d%d)%a?)");
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
return false;
end
-- LOCAL: do not use mw.ustring: it allows full-width characters for %d.
elseif date_string:match("^[1-9]%d%d%d年[1-9]%d?月[1-9]%d?日$") then -- zh: year month day
year, month, day=date_string:match("(%d%d%d%d)年(%d%d*月)(%d%d*)日");
month = get_month_number (month);
if 0 == month then return false; end
anchor_year = year;
elseif date_string:match("^[1-9]%d%d%d年[1-9]%d?月$") then -- zh: year month
year, month=date_string:match("(%d%d%d%d)年(%d%d*月)");
month = get_month_number (month);
if 0 == month then return false; end
anchor_year = year;
elseif date_string:match("^[1-9]%d%d%d?年$") then -- zh: year; here accept either YYY or YYYY
year=date_string:match("(%d%d%d%d?)年");
if false == is_valid_year(year) then
return false;
end
anchor_year = year;
elseif date_string:match("^%d%d%d%d%-%d%d$") then -- numerical year month format
year, month=date_string:match("(%d%d%d%d)%-(%d%d)");
month=tonumber(month);
if 12 < month or 1 > month or 1583 > tonumber(year) then return false; end -- month number not valid or not Gregorian calendar
anchor_year = year;
-- END LOCAL
else
return false; -- date format not one of the MOS:DATE approved formats
end
local anchor_year; -- 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 good_date = false;
if is_set(v) then -- if the parameter has a value
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?"); -- get the year portion so it can be tested
if 'date'==k then
end
elseif 'date'==k then -- if the parameter is |date=
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
elseif v:match("^nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator
else
good_date, anchor_year, COinS_date = check_date (v, tCOinS_date); -- go test the date
end
elseif 'access-date'==k then -- if the parameter is |date=
good_date = check_date (v); -- go test the date
if true == good_date then -- if the date is a valid date
good_date, embargo_date = is_valid_embargo_date is_valid_accessdate (v); -- is |embargo= Wikipedia start date a single dmy, mdy, or ymd formatted < accessdate < tomorrow's date? yes:returns embargo; no: returns 9999
end
else -- any other date-holding parameter
end
end
return anchor_year, embargo_date, error_message; -- and done
end
year = year_string:match ('(%d%d%d%d?)');
if date_string:match ('%d%d%d%d%-%d%d%-%d%d') and year_string:match ('%d%d%d%d%a') then --special case where both date and year are required YYYY-MM-DD and YYYYx
date1 = date_string:match ('(%d%d%d%d)');
year = year_string:match ('(%d%d%d%d)');
end
elseif date_string:match ("%d%d%d%d?.-%d%d%d%d?") then -- any of the standard range formats of date with two three- or four-digit years
date1, date2 = date_string:match ("(%d%d%d%d?).-(%d%d%d%d?)");
if year ~= date1 and year ~= date2 then
end
elseif mw.ustring.date_string:match(date_string, "%d%d%d%d[%s%-–]+%d%d") then -- YYYY-YY date ranges
local century;
date1, century, date2 = mw.ustring.date_string:match(date_string, "((%d%d)%d%d)[%s%-–]+(%d%d)");
date2 = century..date2; -- convert YY to YYYY
if year ~= date1 and year ~= date2 then
result = 0;
end
end
return result;
end