Line 6: |
Line 6: |
| ]] | | ]] |
| | | |
− | local is_set, in_array; -- imported function from selected Module:Citation/CS1/Utilities | + | 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 >---------------------------------------- | | --[=[-------------------------< I S _ V A L I D _ A C C E S S D A T E >---------------------------------------- |
Line 36: |
Line 36: |
| 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 | + | 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); -- convert to numbers for the comparison | + | access_ts = tonumber (access_ts) or lang:parseFormattedNumber (access_ts); -- convert to numbers for the comparison; |
− | tomorrow_ts = tonumber (tomorrow_ts); | + | tomorrow_ts = tonumber (tomorrow_ts) or lang:parseFormattedNumber (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 |
Line 58: |
Line 58: |
| | | |
| local function get_month_number (month) | | local function get_month_number (month) |
− | 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};
| + | return cfg.date_names['local'].long[month] or cfg.date_names['local'].short[month] or -- look for local names first |
− | 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};
| + | cfg.date_names['en'].long[month] or cfg.date_names['en'].short[month] or -- failing that, look for English names |
− | return long_months[month] or -- if month is the long-form name
| + | 0; -- not a recognized month name |
− | short_months[month] or -- if month is the short-form name | |
− | 0; -- misspelled, improper case, or not a month name
| |
| end | | end |
| | | |
Line 88: |
Line 86: |
| | | |
| 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) |
− | local season_list = {['Winter']=21, ['Spring']=22, ['Summer']=23, ['Fall']=24, ['Autumn']=24}; -- make sure these numbers do not overlap month numbers
| + | return cfg.date_names['local'].season[season] or -- look for local names first |
− | local temp;
| + | cfg.date_names['en'].season[season] or -- failing that, look for English names |
− | temp=season_list[season];
| + | 0; -- not a recognized season name |
− | 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 |
| | | |
Line 106: |
Line 113: |
| | | |
| local function is_proper_name (name) | | local function is_proper_name (name) |
− | local name_list = {['Christmas']=31}
| + | return cfg.date_names['local'].named[name] or -- look for local names dates first |
− | local temp; | + | cfg.date_names['en'].named[name] or -- failing that, look for English names |
− | temp=name_list[name];
| + | 0; -- not a recognized named date |
− | 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 |
| | | |
Line 211: |
Line 216: |
| 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. |
| | | |
− | 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, ...,
| + | All season ranges are accepted as valid because there are publishers out there who have published a Summer–Spring YYYY issue so ... ok |
− | 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.
| |
| | | |
| ]] | | ]] |
Line 221: |
Line 225: |
| | | |
| if 0 == range_start_number then -- is this a month range? | | 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 | + | 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 | | range_end_number = get_season_number (range_end); -- get end season number |
| | | |
− | if 0 ~= range_start_number then -- is start of range a season? | + | if (0 ~= range_start_number) and (0 ~= range_end_number) then |
− | if range_start_number < range_end_number then -- range_start is a season | + | return true; -- any season pairing is accepted |
− | return true; -- return true when range_end is also a season and follows start season; else false
| |
− | end
| |
− | if 24 == range_start_number and 21 == range_end_number then -- special case when season range is Fall-Winter or Autumn-Winter
| |
− | return true;
| |
− | end
| |
| end | | end |
− | 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 | + | return false; -- range_start and/or range_end is not a season |
| end | | end |
− | | + | -- here when range_start is a month |
| range_end_number = get_month_number (range_end); -- get end month number | | 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? |
Line 264: |
Line 263: |
| The input table has: | | The input table has: |
| year, year2 – always present; if before 1582, ignore months and days if present | | 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; 31– proper name dates | + | 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 | | day, day2 – 0 if not provided, 1-31 for days |
| | | |
Line 277: |
Line 276: |
| 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 |
| + | -- 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 | | if 1582 > tonumber(input.year) or 20 < tonumber(input.month) then -- Julian calendar or season so &rft.date gets year only |
Line 284: |
Line 294: |
| end | | end |
| if 20 < tonumber(input.month) then -- if season or propername date | | if 20 < tonumber(input.month) then -- if season or propername date |
− | local season = {[21]='winter', [22]='spring', [23]='summer', [24]='fall', [31]='Christmas'}; -- seasons lowercase, no autumn; proper names use title case | + | 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 0 == input.month2 then -- single season date |
| if 30 <tonumber(input.month) then | | if 30 <tonumber(input.month) then |
Line 366: |
Line 376: |
| 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 | | 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 |
| 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 |
− | 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=mw.ustring.match(date_string, "(%D-) +(%d%d?),%s*((%d%d%d%d?)%a?)"); |
− | 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, "^%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 | + | 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 |
− | month, day, day2, anchor_year, year=mw.ustring.match(date_string, "(%a+) +(%d%d?)[%-–](%d%d?), +((%d%d%d%d)%a?)"); | + | month, day, day2, anchor_year, year=mw.ustring.match(date_string, "(%D-) +(%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); |
Line 380: |
Line 389: |
| year2=year; | | year2=year; |
| | | |
− | elseif date_string:match("^[1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day-initial: day month year | + | elseif mw.ustring.match(date_string, "^[1-9]%d? +%D- +[1-9]%d%d%d%a?$") then -- day-initial: day month year |
− | day, month, anchor_year, year=string.match(date_string, "(%d%d*)%s*(%a+)%s*((%d%d%d%d)%a?)"); | + | day, month, anchor_year, year=mw.ustring.match(date_string, "(%d%d*)%s*(%D-) +((%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 |
| + | |
| + | --[[ NOT supported at en.wiki |
| + | elseif mw.ustring.match(date_string, "^[1-9]%d%d%d%a? +%D- +%d%d?$") then -- year-initial: year month day; day: 1 or 2 two digits, leading zero allowed |
| + | anchor_year, year, month, day=mw.ustring.match(date_string, "((%d%d%d%d?)%a?) +(%D-) +(%d%d?)"); |
| 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 |
| + | -- end NOT supported at en.wiki ]] |
| | | |
− | elseif mw.ustring.match(date_string, "^[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 | + | 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 |
− | day, day2, month, anchor_year, year=mw.ustring.match(date_string, "(%d%d?)[%-–](%d%d?) +(%a+) +((%d%d%d%d)%a?)"); | + | day, day2, month, anchor_year, year=mw.ustring.match(date_string, "(%d%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); |
Line 393: |
Line 409: |
| year2=year; | | year2=year; |
| | | |
− | elseif mw.ustring.match(date_string, "^[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 | + | 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 |
− | day, month, day2, month2, anchor_year, year=mw.ustring.match(date_string, "(%d%d?) +(%a+) [%-–] (%d%d?) +(%a+) +((%d%d%d%d)%a?)"); | + | day, month, day2, month2, anchor_year, year=mw.ustring.match(date_string, "(%d%d?) +(%D-) +[%-–] +(%d%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 -- 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); -- for metadata |
Line 400: |
Line 416: |
| year2=year; | | year2=year; |
| | | |
− | elseif mw.ustring.match(date_string, "^%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 | + | 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 |
− | month, day, month2, day2, anchor_year, year=mw.ustring.match(date_string, "(%a+) +(%d%d?) [%-–] (%a+) +(%d%d?), +((%d%d%d%d)%a?)"); | + | month, day, month2, day2, anchor_year, year=mw.ustring.match(date_string, "(%D-) +(%d%d?) +[%-–] +(%D-) +(%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); -- for metadata |
Line 407: |
Line 423: |
| year2=year; | | year2=year; |
| | | |
− | elseif mw.ustring.match(date_string, "^[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 | + | 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 |
− | day, month, year, day2, month2, anchor_year, year2=mw.ustring.match(date_string, "(%d%d?) +(%a+) +(%d%d%d%d?) [%-–] (%d%d?) +(%a+) +((%d%d%d%d?)%a?)"); | + | 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?)"); |
| 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 |
Line 414: |
Line 430: |
| month2 = get_month_number (month2); | | month2 = get_month_number (month2); |
| | | |
− | elseif mw.ustring.match(date_string, "^%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 | + | 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 |
− | month, day, year, month2, day2, anchor_year, year2=mw.ustring.match(date_string, "(%a+) +(%d%d?), +(%d%d%d%d) [%-–] (%a+) +(%d%d?), +((%d%d%d%d)%a?)"); | + | 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?)"); |
| 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 |
Line 421: |
Line 437: |
| month2 = get_month_number (month2); | | month2 = get_month_number (month2); |
| | | |
− | elseif mw.ustring.match(date_string, "^%a+ +[1-9]%d%d%d[%-–]%d%d%a?$") then -- special case Winter/Summer year-year (YYYY-YY); year separated with unspaced endash | + | 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 |
| local century; | | local century; |
− | month, year, century, anchor_year, year2=mw.ustring.match(date_string, "(%a+) +((%d%d)%d%d)[%-–]((%d%d)%a?)"); | + | month, year, century, anchor_year, year2=mw.ustring.match(date_string, "(%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 | | 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 |
Line 431: |
Line 447: |
| month = get_season_number (month); | | month = get_season_number (month); |
| | | |
− | elseif mw.ustring.match(date_string, "^%a+ +[1-9]%d%d%d[%-–][1-9]%d%d%d%a?$") then -- special case Winter/Summer year-year; year separated with unspaced endash | + | 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 |
− | month, year, anchor_year, year2=mw.ustring.match(date_string, "(%a+) +(%d%d%d%d)[%-–]((%d%d%d%d)%a?)"); | + | month, year, anchor_year, year2=mw.ustring.match(date_string, "(%D-) +(%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 | | 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 |
Line 439: |
Line 455: |
| month = get_season_number (month); -- for metadata | | month = get_season_number (month); -- for metadata |
| | | |
− | elseif mw.ustring.match(date_string, "^%a+ +[1-9]%d%d%d +[%-–] +%a+ +[1-9]%d%d%d%a?$") then -- month/season year - month/season year; separated by spaced endash | + | 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 |
− | month, year, month2, anchor_year, year2=mw.ustring.match(date_string, "(%a+) +(%d%d%d%d) +[%-–] +(%a+) +((%d%d%d%d)%a?)"); | + | month, year, month2, anchor_year, year2=mw.ustring.match(date_string, "(%D-) +(%d%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 |
Line 454: |
Line 470: |
| end | | end |
| | | |
− | elseif mw.ustring.match(date_string, "^%a+[%-–]%a+ +[1-9]%d%d%d%a?$") then -- month/season range year; months separated by endash | + | elseif mw.ustring.match(date_string, "^%D-[%-–]%D- +[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, "(%a+)[%-–](%a+)%s*((%d%d%d%d)%a?)"); | + | month, month2, anchor_year, year=mw.ustring.match(date_string, "(%D-)[%-–](%D-)%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 |
| if 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season | | if 0 ~= get_month_number(month) then -- determined to be a valid range so just check this one to know if month or season |
Line 466: |
Line 482: |
| year2=year; | | year2=year; |
| | | |
− | elseif date_string:match("^%a+ +%d%d%d%d%a?$") then -- month/season year or proper-name year | + | elseif mw.ustring.match(date_string, "^%D- +%d%d%d%d%a?$") then -- month/season year or proper-name year |
− | month, anchor_year, year=date_string:match("(%a+)%s*((%d%d%d%d)%a?)"); | + | month, anchor_year, year=mw.ustring.match(date_string, "(%D-)%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 |
Line 560: |
Line 576: |
| | | |
| 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) then -- if the parameter has a value | + | if is_set(v.val) 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= | + | v.val = mw.ustring.gsub (v.val, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9 |
− | local year = v:match("c%. ([1-9]%d%d%d?)%a?"); -- get the year portion so it can be tested | + | 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.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:match("((c%. [1-9]%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter | + | anchor_year, COinS_date = v.val: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 |
Line 570: |
Line 587: |
| end | | end |
| elseif 'date'==k then -- if the parameter is |date= | | 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 | + | if v.val: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.val: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 | + | elseif v.val: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.val: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); -- go test the date | + | good_date, anchor_year, COinS_date = check_date (v.val, tCOinS_date); -- go test the date |
| end | | end |
| elseif 'year'==k then -- if the parameter is |year= it should hold only a year value | | elseif 'year'==k then -- if the parameter is |year= it should hold only a year value |
− | if v:match("^[1-9]%d%d%d?%a?$") then -- if |year= 3 or 4 digits only with or without a CITEREF disambiguator | + | 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, anchor_year, COinS_date = true, v:match("((%d+)%a?)"); | + | good_date, anchor_year, COinS_date = true, v.val:match("((%d+)%a?)"); |
| end | | end |
| elseif 'access-date'==k then -- if the parameter is |date= | | elseif 'access-date'==k then -- if the parameter is |date= |
− | good_date = check_date (v, nil, true); -- go test the date; nil is a placeholder; true is the test_accessdate flag | + | good_date = check_date (v.val, nil, true); -- go test the date; nil is a placeholder; true is the test_accessdate flag |
| elseif 'embargo'==k then -- if the parameter is |embargo= | | elseif 'embargo'==k then -- if the parameter is |embargo= |
− | good_date = check_date (v); -- go test the date | + | good_date = check_date (v.val); -- go test the date |
| if true == good_date then -- if the date is a valid date | | if true == good_date then -- if the date is a valid date |
− | good_date, embargo_date = is_valid_embargo_date (v); -- is |embargo= date a single dmy, mdy, or ymd formatted date? yes:returns embargo; no: returns 9999 | + | 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 | | end |
| else -- any other date-holding parameter | | else -- any other date-holding parameter |
− | good_date = check_date (v); -- go test the date | + | 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 |
Line 595: |
Line 612: |
| error_message=error_message .. ", "; -- ... add a comma space separator | | error_message=error_message .. ", "; -- ... add a comma space separator |
| end | | end |
− | error_message=error_message .. "|" .. k .. "="; -- add the failed parameter | + | error_message=error_message .. "|" .. v.name .. "="; -- add the failed parameter |
| end | | end |
| end | | end |
Line 662: |
Line 679: |
| | | |
| local source_patterns = { -- this table holds patterns that match allowed date formats used to extract date components | | 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)', | + | ['dmy'] = '^(%d%d?)%s+(%a+)%s+(%d%d%d%d)$', |
− | ['mdy'] = '(%a+)%s+(%d%d?),%s+(%d%d%d%d)', | + | ['mdy'] = '^(%a+)%s+(%d%d?),%s+(%d%d%d%d)$', |
− | ['ymd'] = '(%d%d%d%d)%-(%d%d)-(%d%d)', | + | ['ymd'] = '^(%d%d%d%d)%-(%d%d)-(%d%d)$', |
| } | | } |
| | | |
Line 723: |
Line 740: |
| | | |
| Date ranges, season dates, proper name dates are not currently supported. | | 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 |
| | | |
| ]] | | ]] |
Line 728: |
Line 751: |
| local function reformat_dates (date_parameters_list, format, short) | | local function reformat_dates (date_parameters_list, format, short) |
| local all = false; -- set to false to skip access- and archive-dates | | local all = false; -- set to false to skip access- and archive-dates |
| + | local result = false; |
| local format_str; | | local format_str; |
| local source_date = {}; | | local source_date = {}; |
Line 736: |
Line 760: |
| end | | end |
| | | |
− | for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list | + | for param_name, param_val in pairs (date_parameters_list) do -- for each date-holding parameter in the list |
− | if is_set(param_val) then -- if the parameter has a value | + | if is_set (param_val.val) then -- if the parameter has a value |
− | if not all and in_array (param_name, {'access-date', 'archive-date'}) then -- if access- or archive-date and format not xxx-all | + | 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 |
− | param_val = ''; -- set to empty string so we don't process this date | + | for source, pattern in pairs (source_patterns) do |
− | end
| + | if param_val.val:match (pattern) then |
− | for source, pattern in pairs(source_patterns) do
| + | if 'ymd' == source then |
− | if param_val:match(pattern) then
| + | get_ymd_date_parts (param_val.val, source_date); -- get the date parts into the source_date table |
− | if 'ymd' == source then
| + | elseif 'dmy' == source then |
− | get_ymd_date_parts (param_val, source_date); -- get the date parts into the source_date table
| + | get_dmy_date_parts (param_val.val, source_date); -- get the date parts into the source_date table |
− | elseif 'dmy' == source then
| + | elseif 'mdy' == source then |
− | get_dmy_date_parts (param_val, source_date); -- get the date parts into the source_date table
| + | get_mdy_date_parts (param_val.val, source_date); -- get the date parts into the source_date table |
− | elseif 'mdy' == source then
| + | end |
− | get_mdy_date_parts (param_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 |
− | if 'ymd' == format and 1582 > tonumber(source_date.year) then -- ymd format dates not allowed before 1582
| + | end |
− | return false; -- abandon reformatting
| + | |
− | end
| + | if short then |
− |
| + | format_str = short_formats[format]; |
− | if short then
| + | else |
− | format_str = short_formats[format];
| + | format_str = long_formats[format]; |
− | else
| + | end |
− | format_str = long_formats[format];
| + | -- convert date and save; |
− | end
| + | 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 |
− | -- convert date and save;
| + | result = true; |
− | date_parameters_list[param_name] = mw.text.trim (os.date (format_str, os.time(source_date))); -- strip leading space when single digit day and %e is first format
| + | end -- if |
− | end | + | end -- for |
− | end | + | end -- if |
− | end | + | end -- if |
− | end | + | end -- for |
− | return true; -- declare success and done
| + | return result; -- declare result and done |
| end | | end |
| | | |
Line 783: |
Line 807: |
| local n; | | local n; |
| for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list | | for param_name, param_val in pairs(date_parameters_list) do -- for each date-holding parameter in the list |
− | if not param_val:match ('%d%d%d%d%-%d%d%-%d%d') then -- for those that are not ymd dates | + | if is_set (param_val.val) then |
− | param_val, n = param_val:gsub ('%-', '–'); -- replace any hyphen with ndash
| + | 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) |
− | if 0 ~= n then
| + | param_val.val, n = param_val.val:gsub ('%-', '–'); -- replace any hyphen with ndash |
− | date_parameters_list[param_name] = param_val; -- update the list
| + | if 0 ~= n then |
− | result = true;
| + | date_parameters_list[param_name].val = param_val.val; -- update the list |
| + | result = true; |
| + | end |
| end | | end |
| end | | end |
| end | | end |
− | return result; -- so we know if | + | return result; -- so we know if any hyphens were replaced |
| end | | 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 |
| | | |
| | | |
Line 801: |
Line 875: |
| ]] | | ]] |
| | | |
− | local function set_selected_modules (utilities_page_ptr) | + | local function set_selected_modules (cfg_table_ptr, utilities_page_ptr) |
− | is_set = utilities_page_ptr.is_set; -- import functions from select Module:Citation/CS1/Utilities module | + | 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 select 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 | | end |
| | | |
Line 813: |
Line 888: |
| reformat_dates = reformat_dates, | | reformat_dates = reformat_dates, |
| date_hyphen_to_dash = date_hyphen_to_dash, | | date_hyphen_to_dash = date_hyphen_to_dash, |
| + | date_name_xlate = date_name_xlate, |
| set_selected_modules = set_selected_modules | | set_selected_modules = set_selected_modules |
| } | | } |