webmcp
annotate framework/env/parse/date.lua @ 110:0c4841af07a5
String truncating by counting Unicode codepoints in format.string(...)
(grapheme cluster boundary detection not implemented)
(grapheme cluster boundary detection not implemented)
author | jbe |
---|---|
date | Sun Jan 12 03:57:47 2014 +0100 (2014-01-12) |
parents | 9fdfb27f8e67 |
children |
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 |