| 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
 |