Строка 2: |
Строка 2: |
| local p = {} | | local p = {} |
| | | |
− | | + | --[[--------------------------< I S _ V A L I D _ A C C E S S D A T E >---------------------------------------- |
− | --[[--------------------------< 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/Utilities
| |
− | local 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: | | returns true if: |
Строка 21: |
Строка 14: |
| adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow | | adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow |
| | | |
− | This function does not work if it is fed month names for languages other than English. Wikimedia #time: parser
| + | ]] |
− | apparently doesn't understand non-Engish date month names. This function will always return false when the date
| |
− | contains a non-English month name because good1 is false after the call to lang.formatDate(). To get around that
| |
− | call this function with YYYY-MM-DD format dates.
| |
− | | |
− | ]=] | |
| | | |
| local function is_valid_accessdate (accessdate) | | local function is_valid_accessdate (accessdate) |
Строка 36: |
Строка 24: |
| good2, tomorrow_ts = pcall( lang.formatDate, lang, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow | | 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 | + | if good1 and good2 then |
− | access_ts = tonumber (access_ts) or lang:parseFormattedNumber (access_ts); -- convert to numbers for the comparison; | + | access_ts = tonumber (access_ts); -- convert to numbers for the comparison |
− | tomorrow_ts = tonumber (tomorrow_ts) or lang:parseFormattedNumber (tomorrow_ts); | + | tomorrow_ts = tonumber (tomorrow_ts); |
| else | | else |
| return false; -- one or both failed to convert to unix time stamp | | return false; -- one or both failed to convert to unix time stamp |
| end | | end |
− | | + | |
| if 979516800 <= access_ts and access_ts < tomorrow_ts then -- Wikipedia start date <= accessdate < tomorrow's date | | if 979516800 <= access_ts and access_ts < tomorrow_ts then -- Wikipedia start date <= accessdate < tomorrow's date |
| return true; | | return true; |
Строка 49: |
Строка 37: |
| end | | end |
| end | | end |
− |
| |
| | | |
| --[[--------------------------< G E T _ M O N T H _ N U M B E R >---------------------------------------------- | | --[[--------------------------< G E T _ M O N T H _ N U M B E R >---------------------------------------------- |
Строка 58: |
Строка 45: |
| | | |
| local function get_month_number (month) | | local function get_month_number (month) |
− | return cfg.date_names['local'].long[month] or cfg.date_names['local'].short[month] or -- look for local names first
| + | local long_months = {['January']=1, ['February']=2, ['March']=3, ['April']=4, ['May']=5, ['June']=6, ['July']=7, ['August']=8, ['September']=9, ['October']=10, ['November']=11, ['December']=12}; |
− | cfg.date_names['en'].long[month] or cfg.date_names['en'].short[month] or -- failing that, look for English names
| + | local short_months = {['Jan']=1, ['Feb']=2, ['Mar']=3, ['Apr']=4, ['May']=5, ['Jun']=6, ['Jul']=7, ['Aug']=8, ['Sep']=9, ['Oct']=10, ['Nov']=11, ['Dec']=12}; |
− | 0; -- not a recognized month name | + | local temp; |
| + | temp=long_months[month]; |
| + | if temp then return temp; end -- if month is the long-form name |
| + | temp=short_months[month]; |
| + | if temp then return temp; end -- if month is the short-form name |
| + | return 0; -- misspelled, improper case, or not a month name |
| end | | end |
− |
| |
− |
| |
− | --[[--------------------------< I S _ V A L I D _ E M B A R G O _ D A T E >------------------------------------
| |
− |
| |
− | returns true and date value if that value has proper dmy, mdy, ymd format.
| |
− |
| |
− | returns false and 9999 (embargoed forever) when date value is not proper format; assumes that when |embargo= is
| |
− | set, the editor intended to embargo a pmc but |embargo= does not hold a single date.
| |
− |
| |
− | ]]
| |
− |
| |
− | local function is_valid_embargo_date (v)
| |
− | if v:match ('^%d%d%d%d%-%d%d%-%d%d$') or -- ymd
| |
− | v:match ('^%d%d?%s+%a+%s+%d%d%d%d$') or -- dmy
| |
− | v:match ('^%a+%s+%d%d?%s*,%s*%d%d%d%d$') then -- mdy
| |
− | return true, v;
| |
− | end
| |
− | return false, '9999'; -- if here not good date so return false and set embargo date to long time in future
| |
− | end
| |
− |
| |
| | | |
| --[[--------------------------< G E T _ S E A S O N _ N U M B E R >-------------------------------------------- | | --[[--------------------------< 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 | | 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 |
− |
| |
− | Uses ISO DIS 8601 2016 part 2 §4.7 Divisions of a year for hemishpere-independent seasons:
| |
− | 21-24 = Spring, Summer, Autumn, Winter, independent of “Hemisphere”
| |
− |
| |
− | These additional divisions not currently supported:
| |
− | 25-28 = Spring - Northern Hemisphere, Summer- Northern Hemisphere, Autumn - Northern Hemisphere, Winter - Northern Hemisphere
| |
− | 29-32 = Spring – Southern Hemisphere, Summer– Southern Hemisphere, Autumn – Southern Hemisphere, Winter - Southern Hemisphere
| |
− | 33-36 = Quarter 1, Quarter 2, Quarter 3, Quarter 4 (3 months each)
| |
− | 37-39 = Quadrimester 1, Quadrimester 2, Quadrimester 3 (4 months each)
| |
− | 40-41 = Semestral 1, Semestral-2 (6 months each)
| |
− |
| |
| | | |
| ]] | | ]] |
| | | |
| local function get_season_number (season) | | local function get_season_number (season) |
− | return cfg.date_names['local'].season[season] or -- look for local names first
| + | local season_list = {['Winter']=1, ['Spring']=2, ['Summer']=3, ['Fall']=4, ['Autumn']=4} |
− | cfg.date_names['en'].season[season] or -- failing that, look for English names
| + | local temp; |
− | 0; -- not a recognized season name
| + | temp=season_list[season]; |
| + | if temp then return temp; end -- if season is a valid name return its number |
| + | return 0; -- misspelled, improper case, or not a season name |
| end | | end |
| | | |
Строка 113: |
Строка 76: |
| | | |
| local function is_proper_name (name) | | local function is_proper_name (name) |
− | return cfg.date_names['local'].named[name] or -- look for local names dates first
| + | local name_list = {['Christmas']=1} |
− | cfg.date_names['en'].named[name] or -- failing that, look for English names | + | local temp; |
− | 0; -- not a recognized named date
| + | temp=name_list[name]; |
| + | if temp then return temp; end -- if name is a valid name return its number |
| + | return 0; -- misspelled, improper case, or not a proper name |
| end | | end |
| | | |
Строка 132: |
Строка 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 >---------------------------------------------------- |
Строка 138: |
Строка 104: |
| | | |
| ]] | | ]] |
− | local year_limit;
| + | |
| local function is_valid_year(year) | | local function is_valid_year(year) |
| if not is_set(year_limit) then | | if not is_set(year_limit) then |
Строка 146: |
Строка 112: |
| 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 | + | 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. |
− | 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.
| |
| | | |
| + | 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 |
| | | |
− | month = tonumber(month); -- required for YYYY-MM-DD dates
| + | if (2==month) then -- if February |
− |
| + | month_length = 28; -- then 28 days unless |
− | if (2==month) then -- if February | + | if 1582 > tonumber(year) then -- Julian calendar |
− | 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 -- Gregorian calendar | + | 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; -- if leap year then 29 days in February | + | month_length = 29; -- if leap year then 29 days in February |
| end | | end |
| end | | end |
Строка 216: |
Строка 176: |
| Month pairs are expected to be left to right, earliest to latest in time. | | Month pairs are expected to be left to right, earliest to latest in time. |
| | | |
− | All season ranges are accepted as valid because there are publishers out there who have published a Summer–Spring YYYY issue so ... ok
| + | Similarly, seasons are also left to right, earliest to latest in time. There is an oddity with seasons: winter is assigned a value of 1, spring 2, ..., |
| + | fall and autumn 4. Because winter can follow fall/autumn at the end of a calender year, a special test is made to see if |date=Fall-Winter yyyy (4-1) is the date. |
| | | |
| ]] | | ]] |
Строка 222: |
Строка 183: |
| local function is_valid_month_season_range(range_start, range_end) | | local function is_valid_month_season_range(range_start, range_end) |
| local range_start_number = get_month_number (range_start); | | local range_start_number = get_month_number (range_start); |
− | local range_end_number;
| |
| | | |
− | if 0 == range_start_number then -- is this a month range? | + | if 0 == range_start_number then -- is this a month range? |
− | range_start_number = get_season_number (range_start); -- not a month; is it a season? get start season number | + | local range_start_number = get_season_number (range_start); -- not a month; is it a season? get start season number |
− | range_end_number = get_season_number (range_end); -- get end season number | + | local range_end_number = get_season_number (range_end); -- get end season number |
| | | |
− | if (0 ~= range_start_number) and (0 ~= range_end_number) then | + | if 0 ~= range_start_number then -- is start of range a season? |
− | return true; -- any season pairing is accepted
| + | if range_start_number < range_end_number then -- range_start is a season |
| + | return true; -- return true when range_end is also a season and follows start season; else false |
| + | end |
| + | if 4 == range_start_number and 1 == range_end_number then -- special case when range is Fall-Winter or Autumn-Winter |
| + | return true; |
| + | end |
| end | | end |
− | return false; -- range_start and/or range_end is not a season | + | return false; -- range_start is not a month or a season; or range_start is a season and range_end is not; or improper season sequence |
| end | | end |
− | -- here when range_start is a month
| + | |
− | range_end_number = get_month_number (range_end); -- get end month number | + | local range_end_number = get_month_number (range_end); -- get end month number |
− | if range_start_number < range_end_number then -- range_start is a month; does range_start precede range_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? | | if is_valid_month_range_style (range_start, range_end) then -- do months have the same style? |
| return true; -- proper order and same style | | return true; -- proper order and same style |
| end | | end |
| end | | end |
− | return false; -- range_start month number is greater than or equal to range end number; or range end isn't a month | + | return false; -- range_start month number is greater than or equal to range end number; or range end isn't a month |
− | end
| |
− | | |
− | | |
− | --[[--------------------------< M A K E _ C O I N S _ D A T E >------------------------------------------------
| |
− | | |
− | 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
| |
− | 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:
| |
− | single whole dates: yyyy-mm-dd
| |
− | month and year dates: yyyy-mm
| |
− | year dates: yyyy
| |
− | ranges: yyyy-mm-dd/yyyy-mm-dd
| |
− | yyyy-mm/yyyy-mm
| |
− | yyyy/yyyy
| |
− | | |
− | Dates in the Julian calendar are reduced to year or year/year so that we don't have to do calendar conversion from
| |
− | Julian to Proleptic Gregorian.
| |
− | | |
− | 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 Christmas
| |
− | day, day2 – 0 if not provided, 1-31 for days
| |
− |
| |
− | the output table receives:
| |
− | rftdate: an IS8601 formatted date
| |
− | rftchron: a free-form version of the date, usually without year which is in rftdate (season ranges and propername dates)
| |
− | rftssn: one of four season keywords: winter, spring, summer, fall (lowercase)
| |
− | | |
− | ]]
| |
− | | |
− | local function make_COinS_date (input, tCOinS_date)
| |
− | local date; -- one date or first date in a range
| |
− | local date2 = ''; -- end of range date
| |
− | -- start temporary Julian / Gregorian calendar uncertainty detection
| |
− | local year = tonumber(input.year); -- this temporary code to determine the extent of sources dated to the Julian/Gregorian
| |
− | local month = tonumber(input.month); -- interstice 1 October 1582 – 1 January 1926
| |
− | local day = tonumber (input.day);
| |
− | if (0 ~= day) and -- day must have a value for this to be a whole date
| |
− | (((1582 == year) and (10 <= month) and (12 >= month)) or -- any whole 1582 date from 1 october to 31 December or
| |
− | ((1926 == year) and (1 == month) and (1 == input.day)) or -- 1 January 1926 or
| |
− | ((1582 < year) and (1925 >= year))) then -- any date 1 January 1583 – 31 December 1925
| |
− | tCOinS_date.inter_cal_cat = true; -- set category flag true
| |
− | end
| |
− | -- end temporary Julian / Gergorian calendar uncertainty detection
| |
− |
| |
− | if 1582 > tonumber(input.year) or 20 < tonumber(input.month) then -- Julian calendar or season so &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
| |
− | date = string.format ('%.4d/%.4d', tonumber(input.year), tonumber(input.year2)) -- assemble the date range
| |
− | end
| |
− | if 20 < tonumber(input.month) then -- if season or propername date
| |
− | local season = {[24]='winter', [21]='spring', [22]='summer', [23]='fall', [99]='Christmas'}; -- seasons lowercase, no autumn; proper names use title case
| |
− | if 0 == input.month2 then -- single season date
| |
− | if 30 <tonumber(input.month) then
| |
− | tCOinS_date.rftchron = season[input.month]; -- proper name dates
| |
− | else
| |
− | tCOinS_date.rftssn = season[input.month]; -- seasons
| |
− | end
| |
− | else -- season range with a second season specified
| |
− | 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
| |
− | else -- season–season year range
| |
− | tCOinS_date.rftssn = season[input.month]; -- start of range season; keep this?
| |
− | tCOinS_date.rftchron = season[input.month] .. '–' .. season[input.month2]; -- season–season year range
| |
− | end
| |
− | end
| |
− | end
| |
− | tCOinS_date.rftdate = date;
| |
− | return; -- done
| |
− | end
| |
− |
| |
− | if 0 ~= input.day then
| |
− | date = string.format ('%s-%.2d-%.2d', input.year, tonumber(input.month), tonumber(input.day)); -- whole date
| |
− | elseif 0 ~= input.month then
| |
− | date = string.format ('%s-%.2d', input.year, tonumber(input.month)); -- year and month
| |
− | else
| |
− | date = string.format ('%s', input.year); -- just year
| |
− | end
| |
− | | |
− | if 0 ~= input.year2 then
| |
− | if 0 ~= input.day2 then
| |
− | date2 = string.format ('/%s-%.2d-%.2d', input.year2, tonumber(input.month2), tonumber(input.day2)); -- whole date
| |
− | elseif 0 ~= input.month2 then
| |
− | date2 = string.format ('/%s-%.2d', input.year2, tonumber(input.month2)); -- year and month
| |
− | else
| |
− | date2 = string.format ('/%s', input.year2); -- just year
| |
− | end
| |
− | end
| |
− |
| |
− | tCOinS_date.rftdate = date .. date2; -- date2 has the '/' separator
| |
− | return;
| |
| end | | end |
− |
| |
| | | |
| --[[--------------------------< 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 | + | 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. |
− | allowed range separator is endash. Additionally, check the date to see that it is a real date: no 31 in 30-day | + | 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 |
− | months; no 29 February when not a leap year. Months, both long-form and three character abbreviations, and seasons | + | character abbreviations, and seasons must be spelled correctly. Future years beyond next year are not allowed. |
− | 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 | + | 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 |
− | COinS_date. When this happens, the date parameter is used in the COinS metadata and the CITEREF identifier gets | + | 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. |
− | its year from the year parameter if present otherwise CITEREF does not get a date value. | |
| | | |
| Inputs: | | Inputs: |
Строка 358: |
Строка 224: |
| 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 date_string without anchor_year disambiguator if any |
− | | |
| ]] | | ]] |
− | | + | local function check_date (date_string) |
− | local function check_date (date_string, tCOinS_date, test_accessdate) | |
| local year; -- assume that year2, months, and days are not used; | | local year; -- assume that year2, months, and days are not used; |
| local year2=0; -- second year in a year range | | local year2=0; -- second year in a year range |
Строка 374: |
Строка 238: |
| if date_string:match("^%d%d%d%d%-%d%d%-%d%d$") then -- year-initial numerical year month day format | | 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)"); | | 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 > tonumber(year) or 0 == tonumber(day) then return false; end -- month or day number not valid or not Gregorian calendar | + | 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; | | anchor_year = year; |
− | elseif mw.ustring.match(date_string, "^%D- +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial: month day, year | + | |
− | month, day, anchor_year, year=mw.ustring.match(date_string, "(%D-) +(%d%d?),%s*((%d%d%d%d?)%a?)"); | + | elseif date_string:match("^%a+ +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial: month day, year |
| + | month, day, anchor_year, year=string.match(date_string, "(%a+)%s*(%d%d?),%s*((%d%d%d%d)%a?)"); |
| month = get_month_number (month); | | month = get_month_number (month); |
| if 0 == month then return false; end -- return false if month text isn't one of the twelve months | | if 0 == month then return false; end -- return false if month text isn't one of the twelve months |
| | | |
− | elseif mw.ustring.match(date_string, "^%D- +[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 | + | elseif date_string:match("^%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.ustring.match(date_string, "(%D-) +(%d%d?)[%-–](%d%d?), +((%d%d%d%d)%a?)"); | + | month, day, day2, anchor_year, year=string.match(date_string, "(%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; | | 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); | | month = get_month_number (month); |
| if 0 == month then return false; end -- return false if month text isn't one of the twelve months | | if 0 == month then return false; end -- return false if month text isn't one of the twelve months |
− | month2=month; -- for metadata
| |
− | year2=year;
| |
| | | |
− | elseif mw.ustring.match(date_string, "^[1-9]%d? +%D- +[1-9]%d%d%d%a?$") then -- day-initial: day month year | + | elseif date_string:match("^[1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day-initial: day month year |
− | day, month, anchor_year, year=mw.ustring.match(date_string, "(%d%d*)%s*(%D-) +((%d%d%d%d?)%a?)"); | + | day, month, anchor_year, year=string.match(date_string, "(%d%d*)%s*(%a+)%s*((%d%d%d%d)%a?)"); |
| month = get_month_number (month); | | month = get_month_number (month); |
| if 0 == month then return false; end -- return false if month text isn't one of the twelve months | | if 0 == month then return false; end -- return false if month text isn't one of the twelve months |
| | | |
− | elseif mw.ustring.match(date_string, "^[1-9]%d?[%-–][1-9]%d? +%D- +[1-9]%d%d%d%a?$") then -- day-range-initial: day–day month year; days are separated by endash | + | elseif date_string:match("^[1-9]%d?–[1-9]%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.ustring.match(date_string, "(%d%d?)[%-–](%d%d?) +(%D-) +((%d%d%d%d)%a?)"); | + | day, day2, month, anchor_year, year=string.match(date_string, "(%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; | | 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); | | month = get_month_number (month); |
| if 0 == month then return false; end -- return false if month text isn't one of the twelve months | | if 0 == month then return false; end -- return false if month text isn't one of the twelve months |
− | month2=month; -- for metadata
| |
− | year2=year;
| |
| | | |
− | elseif mw.ustring.match(date_string, "^[1-9]%d? +%D- +[%-–] +[1-9]%d? +%D- +[1-9]%d%d%d%a?$") then -- day initial month-day-range: day month - day month year; uses spaced endash | + | elseif date_string:match("^[1-9]%d? +%a+ – [1-9]%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.match(date_string, "(%d%d?) +(%D-) +[%-–] +(%d%d?) +(%D-) +((%d%d%d%d)%a?)"); | + | day, month, day2, month2, anchor_year, year=date_string:match("(%d%d?) +(%a+) – (%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; | | 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 | + | month = get_month_number (month); |
| month2 = get_month_number (month2); | | month2 = get_month_number (month2); |
− | year2=year;
| |
| | | |
− | elseif mw.ustring.match(date_string, "^%D- +[1-9]%d? +[%-–] +%D- +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month initial month-day-range: month day – month day, year; uses spaced endash | + | elseif date_string:match("^%a+ +[1-9]%d? – %a+ +[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.match(date_string, "(%D-) +(%d%d?) +[%-–] +(%D-) +(%d%d?), +((%d%d%d%d)%a?)"); | + | month, day, month2, day2, anchor_year, year=date_string:match("(%a+) +(%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 | | 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 | + | month = get_month_number (month); |
| month2 = get_month_number (month2); | | month2 = get_month_number (month2); |
− | year2=year;
| |
| | | |
− | elseif mw.ustring.match(date_string, "^[1-9]%d? +%D- +[1-9]%d%d%d +[%-–] +[1-9]%d? +%D- +[1-9]%d%d%d%a?$") then -- day initial month-day-year-range: day month year - day month year; uses spaced endash | + | elseif date_string:match("^[1-9]%d? +%a+ +[1-9]%d%d%d – [1-9]%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.match(date_string, "(%d%d?) +(%D-) +(%d%d%d%d) +[%-–] +(%d%d?) +(%D-) +((%d%d%d%d)%a?)"); | + | day, month, year, day2, month2, anchor_year, year2=date_string:match("(%d%d?) +(%a+) +(%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 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 | | 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 |
− | month = get_month_number (month); -- for metadata | + | month = get_month_number (month); |
| month2 = get_month_number (month2); | | month2 = get_month_number (month2); |
| | | |
− | elseif mw.ustring.match(date_string, "^%D- +[1-9]%d?, +[1-9]%d%d%d +[%-–] +%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 | + | elseif date_string:match("^%a+ +[1-9]%d?, +[1-9]%d%d%d – %a+ +[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.match(date_string, "(%D-) +(%d%d?), +(%d%d%d%d) +[%-–] +(%D-) +(%d%d?), +((%d%d%d%d)%a?)"); | + | month, day, year, month2, day2, anchor_year, year2=date_string:match("(%a+) +(%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 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 | | 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 |
− | month = get_month_number (month); -- for metadata | + | month = get_month_number (month); |
| month2 = get_month_number (month2); | | month2 = get_month_number (month2); |
| | | |
− | elseif mw.ustring.match(date_string, "^%D- +[1-9]%d%d%d[%-–]%d%d%a?$") then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash | + | elseif date_string:match("^%a+ +[1-9]%d%d%d–%d%d%a?$") then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash |
| + | if nil == date_string:match("^Winter") and nil == date_string:match("^Summer") then return false end; -- 'month' can only be Winter or Summer |
| local century; | | local century; |
− | month, year, century, anchor_year, year2=mw.ustring.match(date_string, "(%D-) +((%d%d)%d%d)[%-–]((%d%d)%a?)"); | + | year, century, anchor_year, year2=date_string:match("%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 | | anchor_year=year..'–'..anchor_year; -- assemble anchor_year from both years |
| year2 = century..year2; -- add the century to year2 for comparisons | | year2 = century..year2; -- add the century to year2 for comparisons |
| if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later | | if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later |
| 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 |
− | month = get_season_number (month);
| |
| | | |
− | elseif mw.ustring.match(date_string, "^%D- +[1-9]%d%d%d[%-–][1-9]%d%d%d%a?$") then -- special case Winter/Summer year-year; year separated with unspaced endash | + | elseif date_string:match("^%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.match(date_string, "(%D-) +(%d%d%d%d)[%-–]((%d%d%d%d)%a?)"); | + | if nil == date_string:match("^Winter") and nil == date_string:match("^Summer") then return false end; -- 'month' can only be Winter or Summer |
− | if 'Winter' ~= month and 'Summer' ~= month then return false end; -- 'month' can only be Winter or Summer
| + | year, anchor_year, year2=date_string:match("%a+ +(%d%d%d%d)–((%d%d%d%d)%a?)"); |
| anchor_year=year..'–'..anchor_year; -- assemble anchor_year from both years | | anchor_year=year..'–'..anchor_year; -- assemble anchor_year from both years |
| if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later | | if 1 ~= tonumber(year2) - tonumber(year) then return false; end -- must be sequential years, left to right, earlier to later |
| 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 |
− | month = get_season_number (month); -- for metadata
| |
| | | |
− | elseif mw.ustring.match(date_string, "^%D- +[1-9]%d%d%d +[%-–] +%D- +[1-9]%d%d%d%a?$") then -- month/season year - month/season year; separated by spaced endash | + | elseif date_string:match("^%a+ +[1-9]%d%d%d% – %a+ +[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.match(date_string, "(%D-) +(%d%d%d%d) +[%-–] +(%D-) +((%d%d%d%d)%a?)"); | + | month, year, month2, anchor_year, year2=date_string:match("(%a+) +(%d%d%d%d) – (%a+) +((%d%d%d%d)%a?)"); |
| anchor_year=year..'–'..anchor_year; -- assemble anchor_year from both years | | 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 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 0 ~= get_month_number(month) and 0 ~= get_month_number(month2) and is_valid_month_range_style(month, month2) then -- both must be month year, same month style | + | if not((0 ~= get_month_number(month) and 0 ~= get_month_number(month2) and is_valid_month_range_style(month, month2)) or -- both must be month year, same month style |
− | month = get_month_number(month); | + | (0 ~= get_season_number(month) and 0 ~= get_season_number(month2))) then return false; end -- or season year, not mixed |
− | month2 = get_month_number(month2);
| |
− | elseif 0 ~= get_season_number(month) and 0 ~= get_season_number(month2) then -- both must be or season year, not mixed
| |
− | month = get_season_number(month);
| |
− | month2 = get_season_number(month2);
| |
− | else
| |
− | return false;
| |
− | end
| |
| | | |
− | elseif mw.ustring.match(date_string, "^%D-[%-–]%D- +[1-9]%d%d%d%a?$") then -- month/season range year; months separated by endash | + | 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=mw.ustring.match(date_string, "(%D-)[%-–](%D-)%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 |
− | if 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season
| + | return false; |
− | month = get_month_number(month);
| |
− | month2 = get_month_number(month2);
| |
− | else
| |
− | month = get_season_number(month);
| |
− | month2 = get_season_number(month2);
| |
| end | | end |
− | year2=year;
| |
| | | |
− | elseif mw.ustring.match(date_string, "^%D- +%d%d%d%d%a?$") then -- month/season year or proper-name year | + | elseif date_string:match("^%a+ +%d%d%d%d%a?$") then -- month/season year or proper-name year |
− | month, anchor_year, year=mw.ustring.match(date_string, "(%D-)%s*((%d%d%d%d)%a?)"); | + | month, anchor_year, year=date_string:match("(%a+)%s*((%d%d%d%d)%a?)"); |
| if not is_valid_year(year) then return false; end | | 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 | | if not is_valid_month_or_season (month) and 0 == is_proper_name (month) 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
| |
− | month = get_month_number(month);
| |
− | elseif 0 ~= get_season_number(month) then
| |
− | month = get_season_number(month);
| |
− | else
| |
− | month = is_proper_name (month); -- must be proper name; not supported in COinS
| |
− | end
| |
| | | |
− | elseif mw.ustring.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 | + | elseif date_string:match("^[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.match(date_string, "(%d%d%d%d?)[%-–]((%d%d%d%d?)%a?)"); | + | year, anchor_year, year2=date_string:match("(%d%d%d%d?)–((%d%d%d%d?)%a?)"); |
| anchor_year=year..'–'..anchor_year; -- assemble anchor year from both years | | 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 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 |
| | | |
− | elseif mw.ustring.match(date_string, "^[1-9]%d%d%d[%-–]%d%d%a?$") then -- Year range: YYYY–YY; separated by unspaced endash | + | elseif date_string:match("^[1-9]%d%d%d–%d%d%a?$") then -- Year range: YYYY–YY; separated by unspaced endash |
| local century; | | local century; |
− | year, century, anchor_year, year2=mw.ustring.match(date_string, "((%d%d)%d%d)[%-–]((%d%d)%a?)"); | + | year, century, anchor_year, year2=date_string:match("((%d%d)%d%d)–((%d%d)%a?)"); |
| 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 |
Строка 509: |
Строка 347: |
| | | |
| else | | else |
− | return false; -- date format not one of the MOS:DATE approved formats | + | return false; -- date format not one of the MOS:DATE approved formats |
| end | | end |
| | | |
− | if test_accessdate then -- test accessdate here because we have numerical date parts
| + | 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 -- all parts of a single date required
| |
− | 0 == year2 and 0 == month2 and 0 == day2 then -- none of these; accessdate must not be a range
| |
− | if not is_valid_accessdate (year..'-'..month..'-'..day) then
| |
− | return false; -- return false when accessdate out of bounds
| |
− | end
| |
− | else
| |
− | return false; -- return false when accessdate is a range of two dates
| |
− | end
| |
− | end
| |
− | | |
− | 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); |
Строка 541: |
Строка 368: |
| | | |
| if false == result then return false; end | | if false == result then return false; end |
− | | + | -- if here, then date_string is valid; get coins_date from date_string (leave CITEREF disambiguator) ... |
− | if nil ~= tCOinS_date then -- this table only passed into this function when testing |date= parameter values | + | coins_date=date_string:match("^(.+%d)%a?$"); -- last character of valid disambiguatable date is always a digit |
− | make_COinS_date ({year=year, month=month, day=day, year2=year2, month2=month2, day2=day2}, tCOinS_date); -- make an ISO 8601 date string for COinS
| + | coins_date= mw.ustring.gsub(coins_date, "–", "-" ); -- ... and replace any ndash with a hyphen |
− | end
| |
| | | |
− | return true, anchor_year; -- format is good and date string represents a real date | + | return true, anchor_year, coins_date; -- format is good and date string represents a real date |
| end | | end |
− |
| |
| | | |
| --[[--------------------------< D A T E S >-------------------------------------------------------------------- | | --[[--------------------------< D A T E S >-------------------------------------------------------------------- |
Строка 561: |
Строка 386: |
| ]] | | ]] |
| | | |
− | local function dates(date_parameters_list, tCOinS_date) | + | --function p.dates(date_parameters_list) |
| + | local function dates(date_parameters_list) |
| local anchor_year; -- will return as nil if the date being tested is not |date= | | 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 COinS_date; -- will return as nil if the date being tested is not |date= |
− | local embargo_date; -- if embargo date is a good dmy, mdy, ymd date then holds original value else reset to 9999
| |
| local error_message = ""; | | local error_message = ""; |
| + | local mismatch = 0; |
| local good_date = false; | | local good_date = false; |
| | | |
− | for k, v in pairs(date_parameters_list) do -- for each date-holding parameter in the list | + | for k, v in pairs(date_parameters_list) do -- for each date-holding parameter in the list |
− | if is_set(v.val) then -- if the parameter has a value | + | if is_set(v) then -- if the parameter has a value |
− | v.val = mw.ustring.gsub (v.val, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9
| + | 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= |
− | if v.val: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 |
− | local year = v.val: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.val: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 |
| good_date = is_valid_year(year); | | good_date = is_valid_year(year); |
| elseif 'year'==k then | | elseif 'year'==k then |
| good_date = is_valid_year(year); | | good_date = is_valid_year(year); |
| end | | end |
− | elseif 'date'==k then -- if the parameter is |date= | + | elseif 'date'==k then -- if the parameter is |date= |
− | if v.val:match("^n%.d%.%a?$") then -- if |date=n.d. with or without a CITEREF disambiguator | + | 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.val: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.val:match("^nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator | + | elseif v:match("^nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator |
− | good_date, anchor_year, COinS_date = true, v.val: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.val, tCOinS_date); -- go test the date | + | good_date, anchor_year, COinS_date = check_date (v); -- go test the date |
| end | | end |
− | elseif 'year'==k then -- if the parameter is |year= it should hold only a year value | + | elseif 'accessdate'==k then -- if the parameter is |date= |
− | if v.val:match("^[1-9]%d%d%d?%a?$") then -- if |year= 3 or 4 digits only with or without a CITEREF disambiguator | + | good_date = check_date (v); -- go test the date |
− | good_date, anchor_year, COinS_date = true, v.val:match("((%d+)%a?)"); | + | if true == good_date then -- if the date is a valid date |
| + | good_date = is_valid_accessdate (v); -- is Wikipedia start date < accessdate < tomorrow's date? |
| end | | end |
− | elseif 'access-date'==k then -- if the parameter is |date=
| + | else -- any other date-holding parameter |
− | good_date = check_date (v.val, nil, true); -- go test the date; nil is a placeholder; true is the test_accessdate flag
| + | good_date = check_date (v); -- go test the date |
− | elseif 'embargo'==k then -- if the parameter is |embargo=
| |
− | good_date = check_date (v.val); -- go test the date
| |
− | if true == good_date then -- if the date is a valid date
| |
− | good_date, embargo_date = is_valid_embargo_date (v.val); -- is |embargo= date a single dmy, mdy, or ymd formatted date? yes:returns embargo; no: returns 9999
| |
− | end
| |
− | else -- any other date-holding parameter | |
− | good_date = check_date (v.val); -- go test the date | |
| end | | end |
− | if false==good_date then -- assemble one error message so we don't add the tracking category multiple times | + | 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 -- once we've added the first portion of the error message ... | + | if is_set(error_message) then -- once we've added the first portion of the error message ... |
− | error_message=error_message .. ", "; -- ... add a comma space separator | + | error_message=error_message .. ", "; -- ... add a comma space separator |
| end | | end |
− | local failed_parameter = v.name;
| + | error_message=error_message .. "|" .. k .. "="; -- add the failed parameter |
− | if failed_parameter == "" then -- костыль для рувики
| |
− | failed_parameter = "month";
| |
− | end
| |
− | error_message=error_message .. "|" .. failed_parameter .. "="; -- add the failed parameter | |
| end | | end |
| end | | end |
| end | | end |
− | return anchor_year, embargo_date, error_message; -- and done | + | return anchor_year, COinS_date, error_message, mismatch; -- 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 >------------------------------------------------ |
Строка 634: |
Строка 448: |
| year = year_string:match ('(%d%d%d%d?)'); | | 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 | + | 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 date and year required YYYY-MM-DD and YYYYx |
| date1 = date_string:match ('(%d%d%d%d)'); | | date1 = date_string:match ('(%d%d%d%d)'); |
| year = year_string:match ('(%d%d%d%d)'); | | year = year_string:match ('(%d%d%d%d)'); |
Строка 643: |
Строка 457: |
| end | | 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 | + | elseif date_string:match ("%d%d%d%d?.-%d%d%d%d?") then -- any of the standard formats of date with two three- or four-digit years |
| date1, date2 = date_string:match ("(%d%d%d%d?).-(%d%d%d%d?)"); | | date1, date2 = date_string:match ("(%d%d%d%d?).-(%d%d%d%d?)"); |
| if year ~= date1 and year ~= date2 then | | if year ~= date1 and year ~= date2 then |
Строка 649: |
Строка 463: |
| end | | end |
| | | |
− | elseif mw.ustring.match(date_string, "%d%d%d%d[%-–]%d%d") then -- YYYY-YY date ranges | + | elseif date_string:match ("%d%d%d%d[%s%-–]+%d%d") then -- YYYY-YY date ranges |
| local century; | | local century; |
− | date1, century, date2 = mw.ustring.match(date_string, "((%d%d)%d%d)[%-–]+(%d%d)"); | + | date1, century, date2 = date_string:match ("((%d%d)%d%d)[%s%-–]+(%d%d)"); |
| date2 = century..date2; -- convert YY to YYYY | | date2 = century..date2; -- convert YY to YYYY |
| if year ~= date1 and year ~= date2 then | | if year ~= date1 and year ~= date2 then |
Строка 662: |
Строка 476: |
| result = 0; | | result = 0; |
| end | | end |
− | else
| |
− | result = 0; -- no recognizable year in date
| |
| end | | end |
| return result; | | return result; |
| end | | end |
| | | |
− | | + | return {dates = dates, year_date_check = year_date_check} -- return exported functions |
− | --[[-------------------------< R E F O R M A T T A B L E S >------------------------------------------------
| |
− | | |
− | These table are used exclusively for reformatting dates
| |
− | | |
− | ]]
| |
− | | |
− | local source_patterns = { -- this table holds patterns that match allowed date formats used to extract date components
| |
− | ['dmy'] = '^(%d%d?)%s+(%a+)%s+(%d%d%d%d)$',
| |
− | ['mdy'] = '^(%a+)%s+(%d%d?),%s+(%d%d%d%d)$',
| |
− | ['ymd'] = '^(%d%d%d%d)%-(%d%d)-(%d%d)$',
| |
− | }
| |
− | | |
− | local short_formats = { -- this table holds format strings used by os.date() for short month names
| |
− | ['dmy'] = '%e %b %Y',
| |
− | ['mdy'] = '%b %e, %Y',
| |
− | ['ymd'] = '%F',
| |
− | }
| |
− | | |
− | local long_formats = { -- this table holds format strings used by os.date() for long month names
| |
− | ['dmy'] = '%e %B %Y',
| |
− | ['mdy'] = '%B %e, %Y',
| |
− | ['ymd'] = '%F',
| |
− | }
| |
− | | |
− | | |
− | --[[-------------------------< G E T _ D M Y _ D A T E _ P A R T S >------------------------------------------
| |
− | | |
− | extracts year, month and day from DMY formatted date, places them in the source_date table, and returns.
| |
− | | |
− | ]]
| |
− | | |
− | local function get_dmy_date_parts (date, source_date)
| |
− | source_date.day, source_date.month, source_date.year = date:match (source_patterns['dmy']); -- get date components as strings
| |
− | source_date.month = get_month_number (source_date.month); -- get month number
| |
− | end
| |
− | | |
− | | |
− | --[[-------------------------< G E T _ M D Y _ D A T E _ P A R T S >------------------------------------------
| |
− | | |
− | extracts year, month and day from MDY formatted date, places them in the source_date table, and returns.
| |
− | | |
− | ]]
| |
− | | |
− | local function get_mdy_date_parts (date, source_date)
| |
− | source_date.month, source_date.day, source_date.year = date:match (source_patterns['mdy']); -- get date components as strings
| |
− | source_date.month = get_month_number (source_date.month); -- get month number
| |
− | end
| |
− | | |
− | | |
− | --[[-------------------------< G E T _ Y M D _ D A T E _ P A R T S >------------------------------------------
| |
− | | |
− | extracts year, month and day from YMD formatted date, places them in the source_date table, and returns.
| |
− | | |
− | ]]
| |
− | | |
− | local function get_ymd_date_parts (date, source_date)
| |
− | source_date.year, source_date.month, source_date.day = date:match (source_patterns['ymd']); -- get date components as strings
| |
− | end
| |
− | | |
− | | |
− | --[[-------------------------< R E F O R M A T _ D A T E S >--------------------------------------------------
| |
− | | |
− | Reformats existing dates into the format specified by format and short.
| |
− | | |
− | format is one of several keywords: dmy, dmy-all, mdy, mdy-all, ymd, ymd-all. The all version includes access- and
| |
− | archive-dates; otherwise these dates are not reformatted
| |
− | | |
− | Date ranges, season dates, proper name dates are not currently supported.
| |
− | | |
− | For i18n: This code works only at en.wiki because os.date() doesn't support any languages other than English.
| |
− | mw.getContentLanguage():formatDate() will work at non-English wikis only when the date format is yyyy-mm-dd. This is
| |
− | the same issue that plagues is_valid_accessdate()
| |
− | | |
− | It is possible that a solution like that written for ht:Module:Citation/CS1/Date_validation date_name_xlate() could be applied to this problem
| |
− | | |
− | ]]
| |
− | | |
− | local function reformat_dates (date_parameters_list, format, short)
| |
− | local all = false; -- set to false to skip access- and archive-dates
| |
− | local result = false;
| |
− | local format_str;
| |
− | local source_date = {};
| |
− |
| |
− | if format:match('%a+%-all') then
| |
− | format = format:match('(%a+)%-all'); -- extract the format
| |
− | all = true; -- set to true to format access- and archive-dates
| |
− | end
| |
− |
| |
− | for param_name, param_val in pairs (date_parameters_list) do -- for each date-holding parameter in the list
| |
− | if is_set (param_val.val) then -- if the parameter has a value
| |
− | if not (not all and in_array (param_name, {'access-date', 'archive-date'})) then -- skip access- or archive-date unless format is xxx-all; yeah, ugly; TODO: find a better way
| |
− | for source, pattern in pairs (source_patterns) do
| |
− | if param_val.val:match (pattern) then
| |
− | if 'ymd' == source then
| |
− | get_ymd_date_parts (param_val.val, source_date); -- get the date parts into the source_date table
| |
− | elseif 'dmy' == source then
| |
− | get_dmy_date_parts (param_val.val, source_date); -- get the date parts into the source_date table
| |
− | elseif 'mdy' == source then
| |
− | get_mdy_date_parts (param_val.val, source_date); -- get the date parts into the source_date table
| |
− | end
| |
− |
| |
− | if 'ymd' == format and 1582 > tonumber(source_date.year) then -- ymd format dates not allowed before 1582
| |
− | return false; -- abandon reformatting
| |
− | end
| |
− |
| |
− | if short then
| |
− | format_str = short_formats[format];
| |
− | else
| |
− | format_str = long_formats[format];
| |
− | end
| |
− | -- convert date and save;
| |
− | date_parameters_list[param_name].val = mw.text.trim (os.date (format_str, os.time(source_date))); -- strip leading space when single digit day and %e is first format
| |
− | result = true;
| |
− | end -- if
| |
− | end -- for
| |
− | end -- if
| |
− | end -- if
| |
− | end -- for
| |
− | return result; -- declare result and done
| |
− | end
| |
− | | |
− | | |
− | --[[--------------------------< D A T E _ H Y P H E N _ T O _ D A S H >----------------------------------------
| |
− | | |
− | Loops through the list of date-holding parameters and converts any hyphen to an ndash. Not called if the cs1|2
| |
− | template has any date errors.
| |
− | | |
− | Modifies the date_parameters_list and returns true if hyphens are replaced, else returns false.
| |
− | | |
− | ]]
| |
− | | |
− | local function date_hyphen_to_dash (date_parameters_list)
| |
− | local result = false;
| |
− | local n;
| |
− | for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
| |
− | if is_set (param_val.val) then
| |
− | if not mw.ustring.match (param_val.val, '%d%d%d%d%-%d%d%-%d%d') then -- for those that are not ymd dates (ustring because here digits may not be western)
| |
− | param_val.val, n = param_val.val:gsub ('%-', '–'); -- replace any hyphen with ndash
| |
− | if 0 ~= n then
| |
− | date_parameters_list[param_name].val = param_val.val; -- update the list
| |
− | result = true;
| |
− | end
| |
− | end
| |
− | end
| |
− | end
| |
− | return result; -- so we know if any hyphens were replaced
| |
− | end
| |
− | | |
− | | |
− | --[[-------------------------< D A T E _ N A M E _ X L A T E >------------------------------------------------
| |
− | | |
− | Attempts to translate English month names to local-language month names using names supplied by MediaWiki's
| |
− | date parser function. This is simple name-for-name replacement and may not work for all languages.
| |
− | | |
− | if xlat_dig is true, this function will also translate western (English) digits to the local language's digits.
| |
− | This will also translate ymd dates.
| |
− | | |
− | ]]
| |
− | | |
− | local function date_name_xlate (date_parameters_list, xlt_dig)
| |
− | local xlate;
| |
− | local mode; -- long or short month names
| |
− | local modified = false;
| |
− | local date;
| |
− |
| |
− | for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list
| |
− | if is_set(param_val.val) then -- if the parameter has a value
| |
− | date = param_val.val;
| |
− | for month in mw.ustring.gmatch (date, '%a+') do -- iterate through all dates in the date (single date or date range)
| |
− | if cfg.date_names.en.long[month] then
| |
− | mode = 'F'; -- English name is long so use long local name
| |
− | elseif cfg.date_names.en.short[month] then
| |
− | mode = 'M'; -- English name is short so use short local name
| |
− | else
| |
− | mode = nil; -- not an English month name; could be local language month name or an English season name
| |
− | end
| |
− |
| |
− | if mode then -- might be a season
| |
− | xlate = mw.getContentLanguage():formatDate(mode, '1' .. month); -- translate the month name to this local language
| |
− | date = mw.ustring.gsub (date, month, xlate); -- replace the English with the translation
| |
− | date_parameters_list[param_name].val = date; -- save the translated date
| |
− | modified = true; | |
− | end
| |
− | end
| |
− | | |
− | if xlt_dig then -- shall we also translate digits?
| |
− | date = date:gsub ('%d', cfg.date_names.xlate_digits); -- translate digits from western to 'local digits'
| |
− | date_parameters_list[param_name].val = date; -- save the translated date
| |
− | modified = true;
| |
− | end
| |
− | end
| |
− | end
| |
− |
| |
− | return modified;
| |
− | end
| |
− | | |
− | | |
− | --[[--------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------
| |
− | | |
− | Sets local imported functions table to same (live or sandbox) as that used by the other modules.
| |
− | | |
− | ]]
| |
− | | |
− | local function set_selected_modules (cfg_table_ptr, utilities_page_ptr)
| |
− | is_set = utilities_page_ptr.is_set; -- import functions from selected Module:Citation/CS1/Utilities module
| |
− | in_array = utilities_page_ptr.in_array; -- import functions from selected Module:Citation/CS1/Utilities module
| |
− | cfg = cfg_table_ptr; -- import tables from selected Module:Citation/CS1/Configuration
| |
− | end
| |
− | | |
− | | |
− | | |
− | return { -- return exported functions
| |
− | dates = dates,
| |
− | year_date_check = year_date_check,
| |
− | reformat_dates = reformat_dates,
| |
− | date_hyphen_to_dash = date_hyphen_to_dash,
| |
− | date_name_xlate = date_name_xlate,
| |
− | set_selected_modules = set_selected_modules
| |
− | }
| |