| rev | line source | 
| jbe/bsw@0 | 1 local function map_2digit_year(y2) | 
| jbe/bsw@0 | 2   local current_year = atom.date:get_current().year | 
| jbe/bsw@0 | 3   local guess2 = math.floor(current_year / 100) * 100 + tonumber(y2) | 
| jbe/bsw@0 | 4   local guess1 = guess2 - 100 | 
| jbe/bsw@0 | 5   local guess3 = guess2 + 100 | 
| jbe/bsw@0 | 6   if guess1 >= current_year - 80 and guess1 <= current_year + 10 then | 
| jbe/bsw@0 | 7     return guess1 | 
| jbe/bsw@0 | 8   elseif guess2 >= current_year - 80 and guess2 <= current_year + 10 then | 
| jbe/bsw@0 | 9     return guess2 | 
| jbe/bsw@0 | 10   elseif guess3 >= current_year - 80 and guess3 <= current_year + 10 then | 
| jbe/bsw@0 | 11     return guess3 | 
| jbe/bsw@0 | 12   end | 
| jbe/bsw@0 | 13 end | 
| jbe/bsw@0 | 14 | 
| jbe/bsw@0 | 15 function parse.date(str, dest_type, options) | 
| jbe/bsw@0 | 16   if dest_type ~= atom.date then | 
| jbe/bsw@0 | 17     error("parse.date(...) can only return dates, but a different destination type than atom.date was given.") | 
| jbe/bsw@0 | 18   end | 
| jbe/bsw@0 | 19   local date_format = locale.get("date_format") | 
| jbe/bsw@0 | 20   if date_format and string.find(date_format, "Y+%-D+%-M+") then | 
| jbe/bsw@0 | 21     error("Date format collision with ISO standard.") | 
| jbe/bsw@0 | 22   end | 
| jbe/bsw@0 | 23   if string.match(str, "^%s*$") then | 
| jbe/bsw@0 | 24     return nil | 
| jbe/bsw@0 | 25   end | 
| jbe/bsw@0 | 26   -- first try ISO format | 
| jbe/bsw@0 | 27   local year, month, day = string.match( | 
| jbe/bsw@0 | 28     str, "^%s*([0-9][0-9][0-9][0-9])%-([0-9][0-9])%-([0-9][0-9])%s*$" | 
| jbe/bsw@0 | 29   ) | 
| jbe/bsw@0 | 30   if year then | 
| jbe/bsw@0 | 31     return atom.date{ | 
| jbe/bsw@0 | 32       year = tonumber(year), | 
| jbe/bsw@0 | 33       month = tonumber(month), | 
| jbe/bsw@0 | 34       day = tonumber(day) | 
| jbe/bsw@0 | 35     } | 
| jbe/bsw@0 | 36   end | 
| jbe/bsw@0 | 37   if not date_format then | 
| jbe/bsw@0 | 38     return atom.date.invalid | 
| jbe/bsw@0 | 39   end | 
| jbe/bsw@0 | 40   local format_parts = {} | 
| jbe/bsw@0 | 41   local numeric_parts = {} | 
| jbe/bsw@0 | 42   for part in string.gmatch(date_format, "[YMD]+") do | 
| jbe/bsw@0 | 43     format_parts[#format_parts+1] = part | 
| jbe/bsw@0 | 44   end | 
| jbe/bsw@0 | 45   for part in string.gmatch(str, "[0-9]+") do | 
| jbe/bsw@0 | 46     numeric_parts[#numeric_parts+1] = part | 
| jbe/bsw@0 | 47   end | 
| jbe/bsw@0 | 48   if #format_parts ~= #numeric_parts then | 
| jbe/bsw@0 | 49     return atom.date.invalid | 
| jbe/bsw@0 | 50   end | 
| jbe/bsw@0 | 51   local year, month, day | 
| jbe/bsw@0 | 52   local function process_part(format_part, numeric_part) | 
| jbe/bsw@0 | 53     if string.find(format_part, "^Y+$") then | 
| jbe/bsw@0 | 54       if #numeric_part == 4 then | 
| jbe/bsw@0 | 55         year = tonumber(numeric_part) | 
| jbe/bsw@0 | 56       elseif #numeric_part == 2 then | 
| jbe/bsw@0 | 57         year = map_2digit_year(numeric_part) | 
| jbe/bsw@0 | 58       else | 
| jbe/bsw@0 | 59         return atom.date.invalid | 
| jbe/bsw@0 | 60       end | 
| jbe/bsw@0 | 61     elseif string.find(format_part, "^M+$") then | 
| jbe/bsw@0 | 62       month = tonumber(numeric_part) | 
| jbe/bsw@0 | 63     elseif string.find(format_part, "^D+$") then | 
| jbe/bsw@0 | 64       day = tonumber(numeric_part) | 
| jbe/bsw@0 | 65     else | 
| jbe/bsw@0 | 66       if not #format_part == #numeric_part then | 
| jbe/bsw@0 | 67         return atom.date.invalid | 
| jbe/bsw@0 | 68       end | 
| jbe/bsw@0 | 69       local year_str  = "" | 
| jbe/bsw@0 | 70       local month_str = "" | 
| jbe/bsw@0 | 71       local day_str   = "" | 
| jbe/bsw@0 | 72       for i = 1, #format_part do | 
| jbe/bsw@0 | 73         local format_char = string.sub(format_part, i, i) | 
| jbe/bsw@0 | 74         local number_char = string.sub(numeric_part, i, i) | 
| jbe/bsw@0 | 75         if format_char == "Y" then | 
| jbe/bsw@0 | 76           year_str = year_str .. number_char | 
| jbe/bsw@0 | 77         elseif format_char == "M" then | 
| jbe/bsw@0 | 78           month_str = month_str .. number_char | 
| jbe/bsw@0 | 79         elseif format_char == "D" then | 
| jbe/bsw@0 | 80           day_str = day_str .. number_char | 
| jbe/bsw@0 | 81         else | 
| jbe/bsw@0 | 82           error("Assertion failed.") | 
| jbe/bsw@0 | 83         end | 
| jbe/bsw@0 | 84       end | 
| jbe/bsw@0 | 85       if #year_str == 2 then | 
| jbe/bsw@0 | 86         year = map_2digit_year(year_str) | 
| jbe/bsw@0 | 87       else | 
| jbe/bsw@0 | 88         year = tonumber(year_str) | 
| jbe/bsw@0 | 89       end | 
| jbe/bsw@0 | 90       month = tonumber(month_str) | 
| jbe/bsw@0 | 91       day = tonumber(day_str) | 
| jbe/bsw@0 | 92     end | 
| jbe/bsw@0 | 93   end | 
| jbe/bsw@0 | 94   for i = 1, #format_parts do | 
| jbe/bsw@0 | 95     process_part(format_parts[i], numeric_parts[i]) | 
| jbe/bsw@0 | 96   end | 
| jbe/bsw@0 | 97   if not year or not month or not day then | 
| jbe/bsw@0 | 98     error("Date parser did not determine year, month and day. Maybe the 'date_format' locale is erroneous?") | 
| jbe/bsw@0 | 99   end | 
| jbe/bsw@0 | 100   return atom.date{ year = year, month = month, day = day } | 
| jbe/bsw@0 | 101 end |