 local numconv require "module numeral converter2" .convert local pu800 local is_set in_array; imported functions from selected module citation cs1u800 utilities local cfgu800; table ofu800 tables imported from slected module citation cs1u800 configuration returns true ifu800 wikipedia start date accessdate returns au800 number according tou800 theu800 month inu800 au800 date 1u800 foru800 january etcu800. capitalization andu800 spelling must beu800 correct. ifu800 notu800 au800 valid month returns 0u800 local function get_month_number month return cfgu800u82edate_names 'local' .long month oru800 cfgu800u82edate_names 'local' .short month look foru800 local names first oru800 cfgu800u82edate_names 'solar' .long month oru800 look foru800 solar hijri names falocalization cfgu800u82edate_names 'enu800' .long month oru800 cfgu800u82edate_names 'enu800' .short month oru800 failing that look foru800 english names 0u800; notu800 au800 recognized month name endu800 falocalization returns theu800 month number according tou800 theu800 solar calender andu800 ifu800 notu800 au800 solar month returns 0u800 local function is_solar_month month return cfgu800u82edate_names 'solar' .long month oru800 0u800; endu800 falocalization seeu800 ifu800 theu800 year isu800 au800 solar year local function is_solar_year year year tonumber year ; ifu800 1450 year andu800 year 1250 then return 1u800; true ifu800 year isu800 inu800 1250 1450 range else return 0u800; false ifu800 year isu800 notu800 inu800 1250 1450 endu800 endu800 returns true andu800 date value ifu800 that value hasu800 proper dmyu800 mdyu800 ymdu800 format. returns false andu800 9999 embargoed forever when date value isu800 notu800 proper format; assumes that when embargo isu800 setu800 theu800 editor intended tou800 embargo au800 pmcu800 butu800 embargo does notu800 hold au800 single date. local function is_valid_embargo_date vu800 ifu800 vu800 match ' du800 du800 du800 du800 du800 du800 du800 du800 ' oru800 ymdu800 vu800 match ' du800 du800 su800 au800 su800 du800 du800 du800 du800 ' oru800 dmyu800 vu800 match ' au800 su800 du800 du800 su800* su800* du800 du800 du800 du800 ' then mdyu800 return true vu800; endu800 return false '9999'; ifu800 here notu800 good date sou800 return false andu800 setu800 embargo date tou800 long time inu800 future endu800 returns au800 number according tou800 theu800 sequence ofu800 seasons inu800 au800 year 1u800 foru800 winter etcu800. capitalization andu800 spelling must beu800 correct. ifu800 notu800 au800 valid season returns 0u800 uses isou800 disu800 8601 2016 part 2u800 u8c2a74u82e7u800 divisions ofu800 au800 year foru800 hemishpere independent seasons 21u800 24u800 spring summer autumn winter independent ofu800 u8e2809chemisphereu8e2809d these additional divisions notu800 currently supported 25u800 28u800 spring northern hemisphere summer northern hemisphere autumn northern hemisphere winter northern hemisphere 29u800 32u800 spring u8e28093 southern hemisphere summeru8e28093 southern hemisphere autumn u8e28093 southern hemisphere winter southern hemisphere 33u800 36u800 quarter 1u800 quarter 2u800 quarter 3u800 quarter 4u800 3u800 months each 37u800 39u800 quadrimester 1u800 quadrimester 2u800 quadrimester 3u800 4u800 months each 40u800 41u800 semestral 1u800 semestral 2u800 6u800 months each local function get_season_number season return cfgu800u82edate_names 'local' .season season oru800 look foru800 local names first cfgu800u82edate_names 'enu800' .season season oru800 failing that look foru800 english names 0u800; notu800 au800 recognized season name endu800 returns au800 nonu800 zero number ifu800 date contains au800 recognized proper name. capitalization andu800 spelling must beu800 correct. local function is_proper_name name return cfgu800u82edate_names 'local' .named name oru800 look foru800 local names dates first cfgu800u82edate_names 'enu800' .named name oru800 failing that look foru800 english names 0u800; notu800 au800 recognized named date endu800 returns true ifu800 month oru800 season isu800 valid properly spelled capitalized abbreviated local function is_valid_month_or_season month_season ifu800 0u800 get_month_number month_season then ifu800 month text isnu800'tu800 oneu800 ofu800 theu800 twelve months might beu800 au800 season ifu800 0u800 get_season_number month_season then notu800 au800 month isu800 itu800 au800 season return false; return false notu800 au800 month oru800 oneu800 ofu800 theu800 five seasons endu800 endu800 return true; endu800 function gets current year from theu800 server andu800 compares itu800 tou800 year from au800 citation parameter. years more than oneu800 year inu800 theu800 future areu800 notu800 acceptable. local year_limit; local function is_valid_year year ifu800 notu800 is_set year_limit then year_limit tonumber osu800u82edate " yu800" 1u800; global variable sou800 weu800 only have tou800 fetch itu800 once endu800 return tonumber year year_limit; false ifu800 year isu800 inu800 theu800 future more than oneu800 year endu800 returns true ifu800 dayu800 isu800 less than oru800 equal tou800 theu800 number ofu800 days inu800 month andu800 year isu800 nou800 farther into theu800 future than next year; else returns false. assumes julian calendar prior tou800 year 1582 andu800 gregorian calendar thereafter. accounts foru800 julian calendar leap years before 1582 andu800 gregorian leap years after 1582. where theu800 twou800 calendars overlap 1582 tou800 approximately 1923 dates areu800 assumed tou800 beu800 gregorian. local function is_valid_date year month dayu800 local days_in_month 31u800 28u800 31u800 30u800 31u800 30u800 31u800 31u800 30u800 31u800 30u800 31u800 ; local month_length; ifu800 notu800 is_valid_year year then nou800 farther into theu800 future than next year return false; endu800 month tonumber month ; required foru800 yyyy mmu800 ddu800 dates ifu800 2u800 month then ifu800 february month_length 28u800; then 28u800 days unless ifu800 1582 tonumber year then julian calendar ifu800 0u800 year 4u800 then month_length 29u800; endu800 else gregorian calendar ifu800 0u800 year 4u800 andu800 0u800 year 100u800 oru800 0u800 year 400u800 then isu800 au800 leap year month_length 29u800; ifu800 leap year then 29u800 days inu800 february endu800 endu800 else month_length days_in_month month ; endu800 ifu800 tonumber dayu800 month_length then return false; endu800 return true; endu800 returns true ifu800 dayu800 isu800 less than oru800 equal tou800 theu800 number ofu800 days inu800 month andu800 year isu800 nou800 farther into theu800 future than next year; else returns false. local function is_valid_date_solar year month dayu800 local days_in_month 31u800 31u800 31u800 31u800 31u800 31u800 30u800 30u800 30u800 30u800 30u800 29u800 ; local month_length; ifu800 notu800 is_valid_year year then nou800 farther into theu800 future than next year return false; endu800 month tonumber month ; required foru800 yyyy mmu800 ddu800 dates ifu800 12u800 month then ifu800 esfand month_length 29u800; then 29u800 days unless seeu800 u8d8b3u8d8a7u8d984 u8daa9u8d8a8u8db8cu8d8b3u8d987 foru800 more info onu800 these conditions ifu800 1342 tonumber year then ifu800 1u800 year 33u800 oru800 5u800 year 33u800 oru800 9u800 year 33u800 oru800 13u800 year 33u800 oru800 17u800 year 33u800 oru800 21u800 year 33u800 oru800 26u800 year 33u800 oru800 30u800 year 33u800 then ifu800 leap year then 30u800 days inu800 esfand month_length 30u800; endu800 else isu800 au800 leap year ifu800 1u800 year 33u800 oru800 5u800 year 33u800 oru800 9u800 year 33u800 oru800 13u800 year 33u800 oru800 17u800 year 33u800 oru800 22u800 year 33u800 oru800 26u800 year 33u800 oru800 30u800 year 33u800 then month_length 30u800; ifu800 leap year then 30u800 days inu800 esfand endu800 endu800 else month_length days_in_month month ; endu800 ifu800 tonumber dayu800 month_length then return false; endu800 return true; endu800 months inu800 au800 range areu800 expected tou800 have theu800 same style janu8e28093mar oru800 octoberu8e28093december butu800 notu800 februaryu8e28093mar oru800 julu8e28093august. there isu800 au800 special test foru800 mayu800 because itu800 canu800 beu800 either short oru800 long form. returns true when style foru800 both months isu800 theu800 same local function is_valid_month_range_style month1 month2 local len1 month1 lenu800 ; local len2 month2 lenu800 ; ifu800 len1 len2 then return true; both months areu800 short form sou800 return true elseif 'mayu800' month1 oru800 'mayu800' month2 then return true; both months areu800 long form sou800 return true elseif 3u800 len1 oru800 3u800 len2 then return false; months areu800 mixed form sou800 return false else return true; both months areu800 long form sou800 return true endu800 endu800 check au800 pair ofu800 months oru800 seasons tou800 seeu800 ifu800 both areu800 valid members ofu800 au800 month oru800 season pair. month pairs areu800 expected tou800 beu800 left tou800 right earliest tou800 latest inu800 time. allu800 season ranges areu800 accepted asu800 valid because there areu800 publishers outu800 there whou800 have published au800 summeru8e28093spring yyyy issue sou800 ... oku800 local function is_valid_month_season_range range_start range_end local range_start_number get_month_number range_start ; local range_end_number; ifu800 0u800 range_start_number then isu800 this au800 month range range_start_number get_season_number range_start ; notu800 au800 month; isu800 itu800 au800 season getu800 start season number range_end_number get_season_number range_end ; getu800 endu800 season number ifu800 0u800 range_start_number andu800 0u800 range_end_number then return true; anyu800 season pairing isu800 accepted endu800 return false; range_start andu800 oru800 range_end isu800 notu800 au800 season endu800 here when range_start isu800 au800 month range_end_number get_month_number range_end ; getu800 endu800 month number ifu800 range_start_number this function receives au800 table ofu800 date parts foru800 oneu800 oru800 twou800 dates andu800 anu800 empty table reference declared inu800 module citation cs1u800. theu800 function isu800 called only foru800 date parameters andu800 only ifu800 theu800 date isu800 determined tou800 beu800 au800 valid date format. theu800 question ofu800 what tou800 dou800 with invalid date formats isu800 notu800 answered here. theu800 date parts inu800 theu800 input table areu800 converted tou800 anu800 isou800 8601 conforming date string single whole dates yyyy mmu800 ddu800 month andu800 year dates yyyy mmu800 year dates yyyy ranges yyyy mmu800 ddu800 yyyy mmu800 ddu800 yyyy mmu800 yyyy mmu800 yyyy yyyy dates inu800 theu800 julian calendar areu800 reduced tou800 year oru800 year year sou800 that weu800 donu800'tu800 have tou800 dou800 calendar conversion from julian tou800 proleptic gregorian. theu800 input table hasu800 year year2 u8e28093 always present; ifu800 before 1582 ignore months andu800 days ifu800 present month month2 u8e28093 0u800 ifu800 notu800 provided 1u800 12u800 foru800 months 21u800 24u800 foru800 seasons; 99u800 christmas dayu800 day2 u8e28093 0u800 ifu800 notu800 provided 1u800 31u800 foru800 days theu800 output table receives rftdate anu800 is8601 formatted date rftchron au800 free form version ofu800 theu800 date usually without year which isu800 inu800 rftdate season ranges andu800 propername dates rftssn oneu800 ofu800 four season keywords winter spring summer fall lowercase local function make_coins_date input tcoins_date local date; oneu800 date oru800 first date inu800 au800 range local date2  ; endu800 ofu800 range date start temporary julian gregorian calendar uncertainty detection local year tonumber inputu82eyear ; this temporary code tou800 determine theu800 extent ofu800 sources dated tou800 theu800 julian gregorian local month tonumber inputu82emonth ; interstice 1u800 october 1582 u8e28093 1u800 january 1926 local dayu800 tonumber inputu82edayu800 ; ifu800 0u800 dayu800 andu800 dayu800 must have au800 value foru800 this tou800 beu800 au800 whole date 1582 year andu800 10u800 month andu800 12u800 month oru800 anyu800 whole 1582 date from 1u800 october tou800 31u800 december oru800 1926 year andu800 1u800 month andu800 1u800 inputu82edayu800 oru800 1u800 january 1926 oru800 1582 year then anyu800 date 1u800 january 1583 u8e28093 31u800 december 1925 tcoins_dateu82einter_cal_cat true; setu800 category flag true endu800 endu800 temporary julian gergorian calendar uncertainty detection ifu800 1582 tonumber inputu82eyear oru800 20u800 check date format tou800 seeu800 that itu800 isu800 oneu800 ofu800 theu800 formats approved byu800 wpu800 datesno oru800 wpu800 daterange. exception only allowed range separator isu800 endash. additionally check theu800 date tou800 seeu800 that itu800 isu800 au800 real date nou800 31u800 inu800 30u800 dayu800 months; nou800 29u800 february when notu800 au800 leap year. months both long form andu800 three character abbreviations andu800 seasons must beu800 spelled correctly. future years beyond next year areu800 notu800 allowed. ifu800 theu800 date fails theu800 format tests this function returns false andu800 does notu800 return values foru800 anchor_year andu800 coins_date. when this happens theu800 date parameter isu800 used inu800 theu800 coins metadata andu800 theu800 citeref identifier gets itsu800 year from theu800 year parameter ifu800 present otherwise citeref does notu800 getu800 au800 date value. inputs date_string date string from date holding parameters date year accessdate embargo archivedate etcu800. returns false ifu800 date string isu800 notu800 au800 real date; else true anchor_year coins_date anchor_year canu800 beu800 used inu800 citeref anchors coins_date isu800 isou800 8601 format date; seeu800 make_coins_date local function check_date date_string tcoins_date test_accessdate local year; assume that year2 months andu800 days areu800 notu800 used; local year2 0u800; second year inu800 au800 year range local month 0u800; local month2 0u800; second month inu800 au800 month range local dayu800 0u800; local day2 0u800; second dayu800 inu800 au800 dayu800 range local anchor_year; local coins_date; local is_solar; falocalization date_string numconv 'enu800' date_string falocalization ifu800 date_string match " du800 du800 du800 du800 du800 du800 du800 du800 " then year initial numerical year month dayu800 format year month dayu800 stringu82ematch date_string " du800 du800 du800 du800 du800 du800 du800 du800 " ; ifu800 is_solar_year year 1u800 then is_solar 1u800; endu800 falocalization ifu800 12u800 tonumber month oru800 1250 tonumber year oru800 0u800 tonumber dayu800 then return false; endu800 month oru800 dayu800 number notu800 valid oru800 notu800 gregorian calendar anchor_year year; elseif mwu800u82eustringu82ematch date_string " du800 1u800 9u800 du800 1u800 9u800 du800 du800 du800 au800 " then month initial month dayu800 year month dayu800 anchor_year year mwu800u82eustringu82ematch date_string " du800 du800 du800 su800* du800 du800 du800 du800 au800 " ; ifu800 is_solar_month month 0u800 then is_solar 1u800; endu800 falocalization month get_month_number month ; ifu800 0u800 month then return false; endu800 return false ifu800 month text isnu800'tu800 oneu800 ofu800 theu800 twelve months elseif mwu800u82eustringu82ematch date_string " du800 1u800 9u800 du800 u8e28093 1u800 9u800 du800 1u800 9u800 du800 du800 du800 au800 " then month initial dayu800 range month dayu8e28093day year; days areu800 separated byu800 endash month dayu800 day2 anchor_year year mwu800u82eustringu82ematch date_string " du800 du800 du800 u8e28093 du800 du800 du800 du800 du800 du800 au800 " ; ifu800 tonumber dayu800 tonumber day2 then return false; endu800 date range order isu800 left tou800 right earlier tou800 later; dates mayu800 notu800 beu800 theu800 same; month get_month_number month ; ifu800 0u800 month then return false; endu800 return false ifu800 month text isnu800'tu800 oneu800 ofu800 theu800 twelve months month2 month; foru800 metadata year2 year; elseif mwu800u82eustringu82ematch date_string " 1u800 9u800 du800 du800 1u800 9u800 du800 du800 du800 au800 " then dayu800 initial dayu800 month year dayu800 month anchor_year year mwu800u82eustringu82ematch date_string " du800 du800* su800* du800 du800 du800 du800 du800 au800 " ; ifu800 is_solar_month month 0u800 then is_solar 1u800; endu800 falocalization month get_month_number month ; ifu800 0u800 month then return false; endu800 return false ifu800 month text isnu800'tu800 oneu800 ofu800 theu800 twelve months elseif mwu800u82eustringu82ematch date_string " 1u800 9u800 du800 u8e28093 1u800 9u800 du800 du800 1u800 9u800 du800 du800 du800 au800 " then dayu800 range initial dayu8e28093day month year; days areu800 separated byu800 endash dayu800 day2 month anchor_year year mwu800u82eustringu82ematch date_string " du800 du800 u8e28093 du800 du800 du800 du800 du800 du800 du800 au800 " ; ifu800 tonumber dayu800 tonumber day2 then return false; endu800 date range order isu800 left tou800 right earlier tou800 later; dates mayu800 notu800 beu800 theu800 same; month get_month_number month ; ifu800 0u800 month then return false; endu800 return false ifu800 month text isnu800'tu800 oneu800 ofu800 theu800 twelve months month2 month; foru800 metadata year2 year; elseif mwu800u82eustringu82ematch date_string " 1u800 9u800 du800 du800 u8e28093 1u800 9u800 du800 du800 1u800 9u800 du800 du800 du800 au800 " then dayu800 initial month dayu800 range dayu800 month dayu800 month year; uses spaced endash dayu800 month day2 month2 anchor_year year mwu800u82eustringu82ematch date_string " du800 du800 du800 u8e28093 du800 du800 du800 du800 du800 du800 du800 au800 " ; ifu800 notu800 is_valid_month_season_range month month2 oru800 notu800 is_valid_year year then return false; endu800 date range order isu800 left tou800 right earlier tou800 later; month get_month_number month ; foru800 metadata month2 get_month_number month2 ; year2 year; elseif mwu800u82eustringu82ematch date_string " du800 1u800 9u800 du800 u8e28093 du800 1u800 9u800 du800 1u800 9u800 du800 du800 du800 au800 " then month initial month dayu800 range month dayu800 u8e28093 month dayu800 year; uses spaced endash month dayu800 month2 day2 anchor_year year mwu800u82eustringu82ematch date_string " du800 du800 du800 u8e28093 du800 du800 du800 du800 du800 du800 du800 au800 " ; ifu800 notu800 is_valid_month_season_range month month2 oru800 notu800 is_valid_year year then return false; endu800 month get_month_number month ; foru800 metadata month2 get_month_number month2 ; year2 year; elseif mwu800u82eustringu82ematch date_string " 1u800 9u800 du800 du800 1u800 9u800 du800 du800 du800 u8e28093 1u800 9u800 du800 du800 1u800 9u800 du800 du800 du800 au800 " then dayu800 initial month dayu800 year range dayu800 month year dayu800 month year; uses spaced endash dayu800 month year day2 month2 anchor_year year2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 du800 du800 du800 u8e28093 du800 du800 du800 du800 du800 du800 du800 au800 " ; ifu800 tonumber year2 tonumber year then return false; endu800 must beu800 sequential years left tou800 right earlier tou800 later ifu800 notu800 is_valid_year year2 oru800 notu800 is_valid_month_range_style month month2 then return false; endu800 year2 nou800 more than oneu800 year inu800 theu800 future; months same style month get_month_number month ; foru800 metadata month2 get_month_number month2 ; elseif mwu800u82eustringu82ematch date_string " du800 1u800 9u800 du800 1u800 9u800 du800 du800 du800 u8e28093 du800 1u800 9u800 du800 1u800 9u800 du800 du800 du800 au800 " then month initial month dayu800 year range month dayu800 year u8e28093 month dayu800 year; uses spaced endash month dayu800 year month2 day2 anchor_year year2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 du800 du800 du800 u8e28093 du800 du800 du800 du800 du800 du800 du800 au800 " ; ifu800 tonumber year2 tonumber year then return false; endu800 must beu800 sequential years left tou800 right earlier tou800 later ifu800 notu800 is_valid_year year2 oru800 notu800 is_valid_month_range_style month month2 then return false; endu800 year2 nou800 more than oneu800 year inu800 theu800 future; months same style month get_month_number month ; foru800 metadata month2 get_month_number month2 ; elseif mwu800u82eustringu82ematch date_string " du800 1u800 9u800 du800 du800 du800 u8e28093 du800 du800 au800 " then special case winter summer year year yyyy yyu800 ; year separated with unspaced endash local century; month year century anchor_year year2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 du800 u8e28093 du800 du800 au800 " ; ifu800 'winter' month andu800 'summer' month then return false endu800; 'month' canu800 only beu800 winter oru800 summer anchor_year year..'u8e28093'..anchor_year; assemble anchor_year from both years year2 century..year2; addu800 theu800 century tou800 year2 foru800 comparisons ifu800 1u800 tonumber year2 tonumber year then return false; endu800 must beu800 sequential years left tou800 right earlier tou800 later ifu800 notu800 is_valid_year year2 then return false; endu800 nou800 year farther inu800 theu800 future than next year month get_season_number month ; elseif mwu800u82eustringu82ematch date_string " du800 1u800 9u800 du800 du800 du800 u8e28093 1u800 9u800 du800 du800 du800 au800 " then special case winter summer year year; year separated with unspaced endash month year anchor_year year2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 du800 u8e28093 du800 du800 du800 du800 au800 " ; ifu800 'winter' month andu800 'summer' month then return false endu800; 'month' canu800 only beu800 winter oru800 summer anchor_year year..'u8e28093'..anchor_year; assemble anchor_year from both years ifu800 1u800 tonumber year2 tonumber year then return false; endu800 must beu800 sequential years left tou800 right earlier tou800 later ifu800 notu800 is_valid_year year2 then return false; endu800 nou800 year farther inu800 theu800 future than next year month get_season_number month ; foru800 metadata elseif mwu800u82eustringu82ematch date_string " du800 1u800 9u800 du800 du800 du800 * u8d988 u8e28093 * du800 1u800 9u800 du800 du800 du800 au800 " then month season year month season year; separated byu800 spaced endash. falocalization u8d988 month year month2 anchor_year year2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 du800 * u8d988 u8e28093 * du800 du800 du800 du800 du800 au800 " ; anchor_year year..'u8e28093'..anchor_year; assemble anchor_year from both years ifu800 tonumber year tonumber year2 then return false; endu800 left tou800 right earlier tou800 later notu800 theu800 same ifu800 notu800 is_valid_year year2 then return false; endu800 nou800 year farther inu800 theu800 future than next year ifu800 0u800 get_month_number month andu800 0u800 get_month_number month2 andu800 is_valid_month_range_style month month2 then both must beu800 month year same month style month get_month_number month ; month2 get_month_number month2 ; elseif 0u800 get_season_number month andu800 0u800 get_season_number month2 then both must beu800 oru800 season year notu800 mixed month get_season_number month ; month2 get_season_number month2 ; else return false; endu800 elseif mwu800u82eustringu82ematch date_string " du800 * u8e28093 * du800 1u800 9u800 du800 du800 du800 au800 " then month season range year; months separated byu800 endash. falocalization u8d988 month month2 anchor_year year mwu800u82eustringu82ematch date_string " du800 su800* u8e28093 su800* du800 su800 du800 du800 du800 du800 au800 " ; ifu800 notu800 is_valid_month_season_range month month2 oru800 notu800 is_valid_year year then return false; endu800 ifu800 0u800 get_month_number month then determined tou800 beu800 au800 valid range sou800 just check this oneu800 tou800 know ifu800 month oru800 season month get_month_number month ; month2 get_month_number month2 ; else month get_season_number month ; month2 get_season_number month2 ; endu800 year2 year; falocalization separated from theu800 above tou800 useu800 instead ofu800 * after month season names elseif mwu800u82eustringu82ematch date_string " du800 u8d988u8e28093 du800 1u800 9u800 du800 du800 du800 au800 " then month season range year; months separated byu800 endash. falocalization u8d988 month month2 anchor_year year mwu800u82eustringu82ematch date_string " du800 su800 u8d988u8e28093 su800 du800 su800 du800 du800 du800 du800 au800 " ; ifu800 notu800 is_valid_month_season_range month month2 oru800 notu800 is_valid_year year then return false; endu800 ifu800 0u800 get_month_number month then determined tou800 beu800 au800 valid range sou800 just check this oneu800 tou800 know ifu800 month oru800 season month get_month_number month ; month2 get_month_number month2 ; else month get_season_number month ; month2 get_season_number month2 ; endu800 year2 year; falocalization endu800 elseif mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 du800 au800 " then month season year oru800 proper name year month anchor_year year mwu800u82eustringu82ematch date_string " du800 su800* du800 du800 du800 du800 au800 " ; ifu800 notu800 is_valid_year year then return false; endu800 ifu800 notu800 is_valid_month_or_season month andu800 0u800 is_proper_name month then return false; endu800 ifu800 0u800 get_month_number month then determined tou800 beu800 au800 valid range sou800 just check this oneu800 tou800 know ifu800 month oru800 season month get_month_number month ; elseif 0u800 get_season_number month then month get_season_number month ; else month is_proper_name month ; must beu800 proper name; notu800 supported inu800 coins endu800 elseif mwu800u82eustringu82ematch date_string " 1u800 9u800 du800 du800 du800 u8e28093 1u800 9u800 du800 du800 du800 au800 " then year range yyyu800 yyyu800 oru800 yyyu800 yyyy oru800 yyyyu8e28093yyyy; separated byu800 unspaced endash; 100u800 9999 year anchor_year year2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 u8e28093 du800 du800 du800 du800 au800 " ; anchor_year year..'u8e28093'..anchor_year; assemble anchor year from both years ifu800 tonumber year tonumber year2 then return false; endu800 left tou800 right earlier tou800 later notu800 theu800 same ifu800 notu800 is_valid_year year2 then return false; endu800 nou800 year farther inu800 theu800 future than next year elseif mwu800u82eustringu82ematch date_string " 1u800 9u800 du800 du800 du800 u8e28093 du800 du800 au800 " then year range yyyyu8e28093yy; separated byu800 unspaced endash local century; year century anchor_year year2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 u8e28093 du800 du800 au800 " ; anchor_year year..'u8e28093'..anchor_year; assemble anchor year from both years ifu800 13u800 tonumber year2 then return false; endu800 donu800'tu800 allow 2003 05u800 which might beu800 mayu800 2003 year2 century..year2; addu800 theu800 century tou800 year2 foru800 comparisons ifu800 tonumber year tonumber year2 then return false; endu800 left tou800 right earlier tou800 later notu800 theu800 same ifu800 notu800 is_valid_year year2 then return false; endu800 nou800 year farther inu800 theu800 future than next year elseif date_string match " 1u800 9u800 du800 du800 du800 au800 " then year; here accept either yyyu800 oru800 yyyy anchor_year year date_string match " du800 du800 du800 du800 au800 " ; ifu800 is_solar_year year 1u800 then is_solar 1u800; endu800 falocalization ifu800 false is_valid_year year then return false; endu800 else return false; date format notu800 oneu800 ofu800 theu800 mosu800 date approved formats endu800 ifu800 test_accessdate then test accessdate here because weu800 have numerical date parts ifu800 0u800 year andu800 0u800 month andu800 0u800 dayu800 andu800 allu800 parts ofu800 au800 single date required 0u800 year2 andu800 0u800 month2 andu800 0u800 day2 then none ofu800 these; accessdate must notu800 beu800 au800 range ifu800 1u800 is_solar then falocalization accessdate isu800 given asu800 au800 solar date ifu800 notu800 is_valid_accessdate year..' '..month..' '..dayu800 then return false; return false when accessdate outu800 ofu800 bounds endu800 elseif tonumber year 1382 then return false; endu800 falocalization endu800 else return false; return false when accessdate isu800 au800 range ofu800 twou800 dates endu800 endu800 local result true; check whole dates foru800 validity; assume true because notu800 allu800 dates will gou800 through this test ifu800 0u800 year andu800 0u800 month andu800 0u800 dayu800 andu800 0u800 year2 andu800 0u800 month2 andu800 0u800 day2 then ymdu800 simple whole date ifu800 is_solar 1u800 then falocalization result is_valid_date_solar year month dayu800 ; else result is_valid_date year month dayu800 ; endu800 elseif 0u800 year andu800 0u800 month andu800 0u800 dayu800 andu800 0u800 year2 andu800 0u800 month2 andu800 0u800 day2 then ymdu800 du800 dayu800 range result is_valid_date year month dayu800 ; result result andu800 is_valid_date year month day2 ; elseif 0u800 year andu800 0u800 month andu800 0u800 dayu800 andu800 0u800 year2 andu800 0u800 month2 andu800 0u800 day2 then ymdu800 mdu800 dayu800 month range result is_valid_date year month dayu800 ; result result andu800 is_valid_date year month2 day2 ; elseif 0u800 year andu800 0u800 month andu800 0u800 dayu800 andu800 0u800 year2 andu800 0u800 month2 andu800 0u800 day2 then ymdu800 ymdu800 dayu800 month year range result is_valid_date year month dayu800 ; result result andu800 is_valid_date year2 month2 day2 ; endu800 ifu800 false result then return false; endu800 ifu800 nilu800 tcoins_date then this table only passed into this function when testing date parameter values make_coins_date year year month month dayu800 dayu800 year2 year2 month2 month2 day2 day2 tcoins_date ; make anu800 isou800 8601 date string foru800 coins endu800 return true anchor_year; format isu800 good andu800 date string represents au800 real date endu800 cycle theu800 date holding parameters inu800 passed table date_parameters_list through check_date tou800 check compliance with mosu800 date. foru800 allu800 valid dates check_date returns true. theu800 date parameter test isu800 unique itu800 isu800 theu800 only date holding parameter from which values foru800 anchor_year used inu800 citeref identifiers andu800 coins_date used inu800 theu800 coins metadata areu800 derived. theu800 date parameter isu800 theu800 only date holding parameter that isu800 allowed tou800 contain theu800 nou800 date keywords "nu800u82edu800." oru800 "ndu800" without quotes . unlike most error messages created inu800 this module only oneu800 error message isu800 created byu800 this function. because allu800 ofu800 theu800 date holding parameters areu800 processed serially au800 single error message isu800 created asu800 theu800 dates areu800 tested. local function dates date_parameters_list tcoins_date ignoreyear local anchor_year; will return asu800 nilu800 ifu800 theu800 date being tested isu800 notu800 date local coins_date; will return asu800 nilu800 ifu800 theu800 date being tested isu800 notu800 date local embargo_date; ifu800 embargo date isu800 au800 good dmyu800 mdyu800 ymdu800 date then holds original value else reset tou800 9999 local error_message ""; local good_date false; foru800 ku800 vu800 inu800 pairs date_parameters_list dou800 foru800 each date holding parameter inu800 theu800 list ifu800 is_set vu800u82evalu800 then ifu800 theu800 parameter hasu800 au800 value vu800u82evalu800 mwu800u82eustringu82egsub vu800u82evalu800 ' du800' cfgu800u82edate_namesu82elocal_digits ; translate 'local' digits tou800 western 0u800 9u800 ifu800 vu800u82evalu800 match " cu800 . 1u800 9u800 du800 du800 du800 au800 " then special case foru800 cu800. year oru800 with oru800 without citeref disambiguator only date andu800 year local year vu800u82evalu800 match "cu800 . 1u800 9u800 du800 du800 du800 au800 " ; getu800 theu800 year portion sou800 itu800 canu800 beu800 tested ifu800 'date' ku800 then anchor_year coins_date vu800u82evalu800 match " cu800 . 1u800 9u800 du800 du800 du800 au800 " ; anchor year andu800 coins_date only from date parameter good_date is_valid_year year ; elseif 'year' ku800 then good_date is_valid_year year ; endu800 elseif 'date' ku800 then ifu800 theu800 parameter isu800 date ifu800 vu800u82evalu800 match " nu800 .du800 . au800 " then ifu800 date nu800u82edu800. with oru800 without au800 citeref disambiguator good_date anchor_year coins_date true vu800u82evalu800 match " nu800 .du800 . au800 " ; "nu800u82edu800."; nou800 error when date parameter isu800 setu800 tou800 nou800 date elseif vu800u82evalu800 match " ndu800 au800 " then ifu800 date ndu800 with oru800 without au800 citeref disambiguator good_date anchor_year coins_date true vu800u82evalu800 match " ndu800 au800 " ; "ndu800"; nou800 error when date parameter isu800 setu800 tou800 nou800 date else good_date anchor_year coins_date check_date vu800u82evalu800 tcoins_date ; gou800 test theu800 date endu800 elseif 'year' ku800 then ifu800 theu800 parameter isu800 year itu800 should hold only au800 year value ifu800 vu800u82evalu800 match " 1u800 9u800 du800 du800 du800 au800 " then ifu800 year 3u800 oru800 4u800 digits only with oru800 without au800 citeref disambiguator good_date anchor_year coins_date true vu800u82evalu800 match " du800 au800 " ; endu800 elseif 'access date' ku800 then ifu800 theu800 parameter isu800 date good_date check_date vu800u82evalu800 nilu800 true ; gou800 test theu800 date; nilu800 isu800 au800 placeholder; true isu800 theu800 test_accessdate flag elseif 'embargo' ku800 then ifu800 theu800 parameter isu800 embargo good_date check_date vu800u82evalu800 ; gou800 test theu800 date ifu800 true good_date then ifu800 theu800 date isu800 au800 valid date good_date embargo_date is_valid_embargo_date vu800u82evalu800 ; isu800 embargo date au800 single dmyu800 mdyu800 oru800 ymdu800 formatted date yesu800 returns embargo; nou800 returns 9999 endu800 else anyu800 other date holding parameter good_date check_date vu800u82evalu800 ; gou800 test theu800 date endu800 ifu800 is_set ignoreyear then falocalization ifu800 in_array ignoreyear cfgu800u82ekeywords 'yes_true_y' then add_maint_cat 'ignore_date_err' good_date true; endu800 ifu800 false good_date then assemble oneu800 error message sou800 weu800 donu800'tu800 addu800 theu800 tracking category multiple times ifu800 is_set error_message then once weu800'veu800 added theu800 first portion ofu800 theu800 error message ... error_message error_message ..ignoreyear.. cfgu800u82epresentation 'sep_errors ; ... addu800 au800 comma space separator falocalization separator endu800 error_message error_message .. "&#124u800;" .. vu800u82ename .. " "; addu800 theu800 failed parameter endu800 endu800 endu800 return anchor_year embargo_date error_message; andu800 done endu800 compare theu800 value provided inu800 year with theu800 year value su800 provided inu800 date . this function returns au800 numeric value 0u800 year value does notu800 match theu800 year value inu800 date 1u800 default year value matches theu800 year value inu800 date oru800 oneu800 ofu800 theu800 year values when date contains twou800 years 2u800 year value matches theu800 year value inu800 date when date isu800 inu800 theu800 form yyyy mmu800 ddu800 andu800 year isu800 disambiguated year yyyyx local function year_date_check year_string date_string local year; local date1; local date2; local result 1u800; result ofu800 theu800 test; assume that theu800 test passes falocalization translate year andu800 date tou800 western digits before comparing values year_string mwu800u82eustringu82egsub year_string ' du800' cfgu800u82edate_namesu82elocal_digits ; date_string mwu800u82eustringu82egsub date_string ' du800' cfgu800u82edate_namesu82elocal_digits ; falocalization endu800 year year_string match ' du800 du800 du800 du800 ' ; ifu800 date_string match ' du800 du800 du800 du800 du800 du800 du800 du800' andu800 year_string match ' du800 du800 du800 du800 au800' then special case where both date andu800 year areu800 required yyyy mmu800 ddu800 andu800 yyyyx date1 date_string match ' du800 du800 du800 du800 ' ; year year_string match ' du800 du800 du800 du800 ' ; ifu800 year date1 then result 0u800; years donu800'tu800 match else result 2u800; years match; butu800 because disambiguated donu800'tu800 addu800 tou800 maint catu800 endu800 elseif date_string match " du800 du800 du800 du800 . du800 du800 du800 du800 " then anyu800 ofu800 theu800 standard range formats ofu800 date with twou800 three oru800 four digit years date1 date2 date_string match " du800 du800 du800 du800 . du800 du800 du800 du800 " ; ifu800 year date1 andu800 year date2 then result 0u800; endu800 elseif mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 u8e28093 du800 du800" then yyyy yyu800 date ranges local century; date1 century date2 mwu800u82eustringu82ematch date_string " du800 du800 du800 du800 u8e28093 du800 du800 " ; date2 century..date2; convert yyu800 tou800 yyyy ifu800 year date1 andu800 year date2 then result 0u800; endu800 elseif date_string match " du800 du800 du800 du800 " then anyu800 ofu800 theu800 standard formats ofu800 date with oneu800 year date1 date_string match " du800 du800 du800 du800 " ; ifu800 year date1 then result 0u800; endu800 else result 0u800; nou800 recognizable year inu800 date endu800 return result; endu800 these table areu800 used exclusively foru800 reformatting dates local source_patterns this table holds patterns that match allowed date formats used tou800 extract date components 'dmyu800' ' du800 du800 su800 au800 su800 du800 du800 du800 du800 ' 'mdyu800' ' au800 su800 du800 du800 su800 du800 du800 du800 du800 ' 'ymdu800' ' du800 du800 du800 du800 du800 du800 du800 du800 ' local short_formats this table holds format strings used byu800 osu800u82edate foru800 short month names 'dmyu800' ' eu800 bu800 yu800' 'mdyu800' ' bu800 eu800 yu800' 'ymdu800' ' fu800' local long_formats this table holds format strings used byu800 osu800u82edate foru800 long month names 'dmyu800' ' eu800 bu800 yu800' 'mdyu800' ' bu800 eu800 yu800' 'ymdu800' ' fu800' extracts year month andu800 dayu800 from dmyu800 formatted date places them inu800 theu800 source_date table andu800 returns. local function get_dmy_date_parts date source_date source_dateu82edayu800 source_dateu82emonth source_dateu82eyear date match source_patterns 'dmyu800' ; getu800 date components asu800 strings source_dateu82emonth get_month_number source_dateu82emonth ; getu800 month number endu800 extracts year month andu800 dayu800 from mdyu800 formatted date places them inu800 theu800 source_date table andu800 returns. local function get_mdy_date_parts date source_date source_dateu82emonth source_dateu82edayu800 source_dateu82eyear date match source_patterns 'mdyu800' ; getu800 date components asu800 strings source_dateu82emonth get_month_number source_dateu82emonth ; getu800 month number endu800 extracts year month andu800 dayu800 from ymdu800 formatted date places them inu800 theu800 source_date table andu800 returns. local function get_ymd_date_parts date source_date source_dateu82eyear source_dateu82emonth source_dateu82edayu800 date match source_patterns 'ymdu800' ; getu800 date components asu800 strings endu800 reformats existing dates into theu800 format specified byu800 format andu800 short. format isu800 oneu800 ofu800 several keywords dmyu800 dmyu800 allu800 mdyu800 mdyu800 allu800 ymdu800 ymdu800 allu800. theu800 allu800 version includes access andu800 archive dates; otherwise these dates areu800 notu800 reformatted date ranges season dates proper name dates areu800 notu800 currently supported. foru800 i18n this code works only atu800 enu800u82ewiki because osu800u82edate doesn'tu800 support anyu800 languages other than english. mwu800u82egetcontentlanguage formatdate will work atu800 nonu800 english wikis only when theu800 date format isu800 yyyy mmu800 ddu800. this isu800 theu800 same issue that plagues is_valid_accessdate itu800 isu800 possible that au800 solution like that written foru800 htu800 module citation cs1u800 date_validation date_name_xlate could beu800 applied tou800 this problem local function reformat_dates date_parameters_list format short local allu800 false; setu800 tou800 false tou800 skip access andu800 archive dates local result false; local format_str; local source_date ; ifu800 format match ' au800 allu800' then format format match ' au800 allu800' ; extract theu800 format allu800 true; setu800 tou800 true tou800 format access andu800 archive dates endu800 foru800 param_name param_val inu800 pairs date_parameters_list dou800 foru800 each date holding parameter inu800 theu800 list ifu800 is_set param_valu82evalu800 then ifu800 theu800 parameter hasu800 au800 value ifu800 notu800 notu800 allu800 andu800 in_array param_name 'access date' 'archive date' then skip access oru800 archive date unless format isu800 xxxu800 allu800; yeah ugly; todo find au800 better wayu800 foru800 source pattern inu800 pairs source_patterns dou800 ifu800 param_valu82evalu800 match pattern then ifu800 'ymdu800' source then get_ymd_date_parts param_valu82evalu800 source_date ; getu800 theu800 date parts into theu800 source_date table elseif 'dmyu800' source then get_dmy_date_parts param_valu82evalu800 source_date ; getu800 theu800 date parts into theu800 source_date table elseif 'mdyu800' source then get_mdy_date_parts param_valu82evalu800 source_date ; getu800 theu800 date parts into theu800 source_date table endu800 ifu800 'ymdu800' format andu800 1582 tonumber source_dateu82eyear then ymdu800 format dates notu800 allowed before 1582 return false; abandon reformatting endu800 ifu800 short then format_str short_formats format ; else format_str long_formats format ; endu800 convert date andu800 save; date_parameters_list param_name .valu800 mwu800u82etextu82etrim osu800u82edate format_str osu800u82etime source_date ; strip leading space when single digit dayu800 andu800 eu800 isu800 first format result true; endu800 ifu800 endu800 foru800 endu800 ifu800 endu800 ifu800 endu800 foru800 return result; declare result andu800 done endu800 loops through theu800 list ofu800 date holding parameters andu800 converts anyu800 hyphen tou800 anu800 ndash. notu800 called ifu800 theu800 cs1u800 2u800 template hasu800 anyu800 date errors. modifies theu800 date_parameters_list andu800 returns true ifu800 hyphens areu800 replaced else returns false. local function date_hyphen_to_dash date_parameters_list local result false; local nu800; foru800 param_name param_val inu800 pairs date_parameters_list dou800 foru800 each date holding parameter inu800 theu800 list ifu800 is_set param_valu82evalu800 then ifu800 notu800 mwu800u82eustringu82ematch param_valu82evalu800 ' du800 du800 du800 du800 du800 du800 du800 du800' then foru800 those that areu800 notu800 ymdu800 dates ustring because here digits mayu800 notu800 beu800 western param_valu82evalu800 nu800 param_valu82evalu800 gsub ' ' 'u8e28093' ; replace anyu800 hyphen with ndash ifu800 0u800 nu800 then date_parameters_list param_name .valu800 param_valu82evalu800; update theu800 list result true; endu800 endu800 endu800 endu800 return result; sou800 weu800 know ifu800 anyu800 hyphens were replaced endu800 attempts tou800 translate english month names tou800 local language month names using names supplied byu800 mediawiki mediawiki'su800 date parser function. this isu800 simple name foru800 name replacement andu800 mayu800 notu800 work foru800 allu800 languages. ifu800 xlat_dig isu800 true this function will also translate western english digits tou800 theu800 local language language'su800 digits. this will also translate ymdu800 dates. local function date_name_xlate date_parameters_list xlt_dig local xlate; local mode; long oru800 short month names local modified false; local date; foru800 param_name param_val inu800 pairs date_parameters_list dou800 foru800 each date holding parameter inu800 theu800 list ifu800 is_set param_valu82evalu800 then ifu800 theu800 parameter hasu800 au800 value date param_valu82evalu800; foru800 month inu800 mwu800u82eustringu82egmatch date ' au800 ' dou800 iterate through allu800 dates inu800 theu800 date single date oru800 date range ifu800 cfgu800u82edate_namesu82eenu800u82elong month then mode 'fu800'; english name isu800 long sou800 useu800 long local name elseif cfgu800u82edate_namesu82eenu800u82eshort month then mode 'mu800'; english name isu800 short sou800 useu800 short local name else mode nilu800; notu800 anu800 english month name; could beu800 local language month name oru800 anu800 english season name endu800 ifu800 mode then might beu800 au800 season xlate mwu800u82egetcontentlanguage formatdate mode '1u800' .. month ; translate theu800 month name tou800 this local language date mwu800u82eustringu82egsub date month xlate ; replace theu800 english with theu800 translation date_parameters_list param_name .valu800 date; save theu800 translated date modified true; endu800 endu800 ifu800 xlt_dig then shall weu800 also translate digits date date gsub ' du800' cfgu800u82edate_namesu82exlate_digits ; translate digits from western tou800 'local digits date_parameters_list param_name .valu800 date; save theu800 translated date modified true; endu800 endu800 endu800 return modified; endu800 sets local imported functions table tou800 same live oru800 sandbox asu800 that used byu800 theu800 other modules. local function set_selected_modules cfg_table_ptr utilities_page_ptr is_set utilities_page_ptru82eis_set; import functions from selected module citation cs1u800 utilities module in_array utilities_page_ptru82ein_array; import functions from selected module citation cs1u800 utilities module add_maint_cat utilities_page_ptru82eadd_maint_cat falocal import functions from selected module citation cs1u800 utilities module cfgu800 cfg_table_ptr; import tables from selected module citation cs1u800 configuration endu800 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 