note description: "Parser facility for dates and times" legal: "See notice at end of class." status: "See notice at end of class." date: "$Date: 2017-03-29 12:26:46 +0000 (Wed, 29 Mar 2017) $" revision: "$Revision: 100065 $" class DATE_TIME_PARSER inherit DATE_TIME_VALIDITY_CHECKER rename year as checker_year, month as checker_month, day as checker_day, hour as checker_hour, minute as checker_minute, fine_second as checker_fine_second export {NONE} all end FIND_SEPARATOR_FACILITY create make feature {NONE} -- Initialization make (c: HASH_TABLE [DATE_TIME_CODE, INTEGER_32]) -- Create parser with date/time code c, months array m, -- days array d, and base century b. require code_exists: c /= Void do code := c ensure code_set: code = c end feature -- Access source_string: detachable STRING_8 -- String to be parsed year: INTEGER_32 -- Year part of source_string require value_parsed: parsed do Result := year_val end month: INTEGER_32 -- Month part of source_string require value_parsed: parsed do Result := month_val end day: INTEGER_32 -- Day part of source_string require value_parsed: parsed do Result := day_val end hour: INTEGER_32 -- Hour part of source_string require value_parsed: parsed do Result := hour_val end minute: INTEGER_32 -- Minute part of source_string require value_parsed: parsed do Result := minute_val end fine_second: REAL_64 -- Seconds part of source_string require value_parsed: parsed do Result := fine_second_val end day_text: detachable STRING_8 -- Text representation of day require value_parsed: parsed do Result := day_text_val end feature -- Status report parsed: BOOLEAN -- Has source_string been parsed? is_set_up: BOOLEAN -- Has parser been set up completely? do Result := (days /= Void) and (months /= Void) and (attached source_string as l_source_string and then not l_source_string.is_empty) end is_date: BOOLEAN -- Does source_string contain a DATE? require string_parsed: parsed do Result := is_correct_date (year, month, day) end is_time: BOOLEAN -- Does source_string contain a TIME? require string_parsed: parsed do Result := is_correct_time (hour, minute, fine_second, False) end is_date_time: BOOLEAN -- Does source_string contain a DATE_TIME? require string_parsed: parsed do Result := is_correct_date_time (year, month, day, hour, minute, fine_second, False) end is_value_valid: BOOLEAN -- Is parsed value valid? do Result := parsed and then (is_date or is_time or is_date_time) end feature -- Status setting set_source_string (s: STRING_8) -- Assign s to source_string. require non_empty_string: s /= Void and then not s.is_empty do source_string := s parsed := False ensure source_set: source_string = s not_parsed: not parsed end set_day_array (d: ARRAY [STRING_8]) -- Set day array to d. require not_void: d /= Void do days := d ensure days_set: days = d end set_month_array (m: ARRAY [STRING_8]) -- Set month array to m. require not_void: m /= Void do months := m ensure months_set: months = m end set_base_century (c: INTEGER_32) -- Set base century to c. require base_century_valid: c /= 0 and (c \\ 100 = 0) do base_century := c ensure base_century_set: base_century = c end feature -- Basic operations parse -- Parse source_string. require setup_complete: is_set_up local pos1, pos2, i, j: INTEGER_32 type: INTEGER_32 second_val: INTEGER_32 s: STRING_8 has_seps: BOOLEAN l_year_now: INTEGER_32 l_is_pm, l_is_pm_computed: BOOLEAN l_hour_val_need_computation: BOOLEAN l_item: detachable DATE_TIME_CODE l_substrg: STRING_8 do check source_string_attached: attached source_string as ss then s := ss.as_upper end l_year_now := (create {C_DATE}).year_now year_val := 1 month_val := 1 day_val := 1 hour_val := 0 minute_val := 0 fine_second_val := 0.to_double pos1 := 1 has_seps := has_separators (s) from i := 1 until pos1 > s.count loop l_item := code.item (i) if l_item = Void then pos1 := s.count + 1 elseif l_item.is_separator_code then i := i + 1 pos1 := pos1 + l_item.count_max else if has_seps then pos2 := find_separator (s, pos1) else pos2 := (pos1 + l_item.count_max - 1) * -1 end l_substrg := extracted_substrings (s, pos1, pos2).substrg if pos2 <= 0 then pos2 := - pos2 + 1 end type := l_item.type inspect type when {DATE_TIME_CODE}.day_numeric_type_code, {DATE_TIME_CODE}.day_numeric_on_2_digits_type_code then day_val := l_substrg.to_integer when {DATE_TIME_CODE}.day_text_type_code then day_text_val := l_substrg when {DATE_TIME_CODE}.year_on_4_digits_type_code then year_val := l_substrg.to_integer when {DATE_TIME_CODE}.year_on_2_digits_type_code then if base_century < 0 then year_val := l_substrg.to_integer - base_century if year_val - l_year_now > 50 then year_val := year_val - 100 elseif l_year_now - year_val > 50 then year_val := year_val + 100 end else year_val := l_substrg.to_integer - base_century end when {DATE_TIME_CODE}.month_numeric_type_code, {DATE_TIME_CODE}.month_numeric_on_2_digits_type_code then month_val := l_substrg.to_integer when {DATE_TIME_CODE}.month_text_type_code then check months_attached: attached months as l_months then from j := 1 until j > 12 loop if l_months.item (j).same_string (l_substrg) then month_val := j end j := j + 1 end end when {DATE_TIME_CODE}.hour_numeric_type_code, {DATE_TIME_CODE}.hour_numeric_on_2_digits_type_code then hour_val := l_substrg.to_integer when {DATE_TIME_CODE}.hour_12_clock_scale_type_code, {DATE_TIME_CODE}.hour_12_clock_scale_on_2_digits_type_code then hour_val := l_substrg.to_integer if l_is_pm_computed then if l_is_pm then hour_val := hour_val + 12 if hour_val = 24 then hour_val := 12 end elseif hour_val = 12 then hour_val := 0 end else l_hour_val_need_computation := True end when {DATE_TIME_CODE}.meridiem_type_code then l_is_pm_computed := True l_is_pm := l_substrg.is_case_insensitive_equal ("PM") when {DATE_TIME_CODE}.minute_numeric_type_code, {DATE_TIME_CODE}.minute_numeric_on_2_digits_type_code then minute_val := l_substrg.to_integer when {DATE_TIME_CODE}.second_numeric_type_code, {DATE_TIME_CODE}.second_numeric_on_2_digits_type_code then second_val := l_substrg.to_integer when {DATE_TIME_CODE}.fractional_second_numeric_type_code then fine_second_val := l_substrg.to_double / (10 ^ (l_substrg.count).to_double) end pos1 := pos2 i := i + 1 end end if l_hour_val_need_computation then if not l_is_pm_computed then if hour_val = 12 then hour_val := 0 end elseif l_is_pm then hour_val := hour_val + 12 if hour_val = 24 then hour_val := 12 end elseif hour_val = 12 then hour_val := 0 end end fine_second_val := fine_second_val + second_val.to_double parsed := True ensure string_parsed: parsed end feature {NONE} -- Implementation year_val: INTEGER_32 month_val: INTEGER_32 day_val: INTEGER_32 hour_val: INTEGER_32 minute_val: INTEGER_32 fine_second_val: REAL_64 day_text_val: detachable STRING_8 code: HASH_TABLE [DATE_TIME_CODE, INTEGER_32] -- Hash table containing the parsed date/time code months: detachable ARRAY [STRING_8] -- Names of months days: detachable ARRAY [STRING_8] -- Names of days base_century: INTEGER_32 -- Base century, used when interpreting 2-digit year -- specifications invariant valid_value_definition: is_value_valid = (parsed and then (is_date or is_time or is_date_time)) valid_value_implies_parsing: is_value_valid implies parsed note copyright: "Copyright (c) 1984-2017, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class DATE_TIME_PARSER
Generated by ISE EiffelStudio