note
	description: "DATE/TIME to STRING conversion"
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date: 2018-04-28 20:34:01 +0000 (Sat, 28 Apr 2018) $"
	revision: "$Revision: 101689 $"

class 
	DATE_TIME_CODE_STRING

create 
	make

feature {NONE} -- Initialization

	default_create
			-- Process instances of classes with no creation clause.
			-- (Default: do nothing.)
			-- (from ANY)
		do
		end
	
feature -- Access

	generating_type: TYPE [detachable DATE_TIME_CODE_STRING]
			-- Type of current object
			-- (type of which it is a direct instance)
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			generating_type_not_void: Result /= Void
		end

	generator: STRING_8
			-- Name of current object's generating class
			-- (base class of the type of which it is a direct instance)
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			generator_not_void: Result /= Void
			generator_not_empty: not Result.is_empty
		end
	
feature -- Comparison

	frozen deep_equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void
			-- or attached to isomorphic object structures?
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.is_deep_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			shallow_implies_deep: standard_equal (a, b) implies Result
			both_or_none_void: (a = Void) implies (Result = (b = Void))
			same_type: (Result and (a /= Void)) implies (b /= Void and then a.same_type (b))
			symmetric: Result implies deep_equal (b, a)
		end

	frozen equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void or attached
			-- to objects considered equal?
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.is_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.is_equal (b))
		end

	frozen is_deep_equal (other: DATE_TIME_CODE_STRING): BOOLEAN
			-- Are Current and other attached to isomorphic object structures?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			shallow_implies_deep: standard_is_equal (other) implies Result
			same_type: Result implies same_type (other)
			symmetric: Result implies other.is_deep_equal (Current)
		end

	is_equal (other: DATE_TIME_CODE_STRING): BOOLEAN
			-- Is other attached to an object considered
			-- equal to current object?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			symmetric: Result implies other ~ Current
			consistent: standard_is_equal (other) implies Result
		end

	frozen standard_equal (a: detachable ANY; b: like arg #1): BOOLEAN
			-- Are a and b either both void or attached to
			-- field-by-field identical objects of the same type?
			-- Always uses default object comparison criterion.
			-- (from ANY)
		do
			if a = Void then
				Result := b = Void
			else
				Result := b /= Void and then a.standard_is_equal (b)
			end
		ensure -- from ANY
			instance_free: class
			definition: Result = (a = Void and b = Void) or else ((a /= Void and b /= Void) and then a.standard_is_equal (b))
		end

	frozen standard_is_equal (other: DATE_TIME_CODE_STRING): BOOLEAN
			-- Is other attached to an object of the same type
			-- as current object, and field-by-field identical to it?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			same_type: Result implies same_type (other)
			symmetric: Result implies other.standard_is_equal (Current)
		end
	
feature -- Status report

	conforms_to (other: ANY): BOOLEAN
			-- Does type of current object conform to type
			-- of other (as per Eiffel: The Language, chapter 13)?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		end

	is_date (s: STRING_8): BOOLEAN
			-- Does s contain a DATE?
		require
			non_empty_string: s /= Void and then not s.is_empty
		do
			Result := parser (s).is_date
		end

	is_date_time (s: STRING_8): BOOLEAN
			-- Does s contain a DATE_TIME?
		require
			non_empty_string: s /= Void and then not s.is_empty
		do
			Result := parser (s).is_date_time
		end

	is_time (s: STRING_8): BOOLEAN
			-- Does s contain a TIME?
		require
			non_empty_string: s /= Void and then not s.is_empty
		do
			Result := parser (s).is_time
		end

	is_value_valid (s: STRING_8): BOOLEAN
			-- Does s contain a valid date or time as string representation?
		require
			non_empty_string: s /= Void and then not s.is_empty
		local
			l_parser: like parser
		do
			l_parser := parser (s)
			Result := l_parser.is_date or l_parser.is_time or l_parser.is_date_time
		end

	same_type (other: ANY): BOOLEAN
			-- Is type of current object identical to type of other?
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		external
			"built_in"
		ensure -- from ANY
			definition: Result = (conforms_to (other) and other.conforms_to (Current))
		end

	separators_used: BOOLEAN
			-- Does the code string contain any separators?
	
feature -- Status setting

	set_base_century (c: INTEGER_32)
			-- Set base century to c.
		require
			base_valid: c > 0 and (c \\ 100 = 0)
		do
			base_century := c
		ensure
			base_century_set: base_century = c
		end
	
feature -- Duplication

	frozen clone (other: detachable ANY): like other
		obsolete "Use `twin' instead. [2017-05-31]"
			-- Void if other is void; otherwise new object
			-- equal to other
			--
			-- For non-void other, clone calls copy;
			-- to change copying/cloning semantics, redefine copy.
			-- (from ANY)
		do
			if other /= Void then
				Result := other.twin
			end
		ensure -- from ANY
			instance_free: class
			equal: Result ~ other
		end

	copy (other: DATE_TIME_CODE_STRING)
			-- Update current object using fields of object attached
			-- to other, so as to yield equal objects.
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
			type_identity: same_type (other)
		external
			"built_in"
		ensure -- from ANY
			is_equal: Current ~ other
		end

	frozen deep_clone (other: detachable ANY): like other
		obsolete "Use `deep_twin' instead. [2017-05-31]"
			-- Void if other is void: otherwise, new object structure
			-- recursively duplicated from the one attached to other
			-- (from ANY)
		do
			if other /= Void then
				Result := other.deep_twin
			end
		ensure -- from ANY
			instance_free: class
			deep_equal: deep_equal (other, Result)
		end

	frozen deep_copy (other: DATE_TIME_CODE_STRING)
			-- Effect equivalent to that of:
			--		copy (other . deep_twin)
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
		do
			copy (other.deep_twin)
		ensure -- from ANY
			deep_equal: deep_equal (Current, other)
		end

	frozen deep_twin: DATE_TIME_CODE_STRING
			-- New object structure recursively duplicated from Current.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			deep_twin_not_void: Result /= Void
			deep_equal: deep_equal (Current, Result)
		end

	frozen standard_clone (other: detachable ANY): like other
		obsolete "Use `standard_twin' instead. [2017-05-31]"
			-- Void if other is void; otherwise new object
			-- field-by-field identical to other.
			-- Always uses default copying semantics.
			-- (from ANY)
		do
			if other /= Void then
				Result := other.standard_twin
			end
		ensure -- from ANY
			instance_free: class
			equal: standard_equal (Result, other)
		end

	frozen standard_copy (other: DATE_TIME_CODE_STRING)
			-- Copy every field of other onto corresponding field
			-- of current object.
			-- (from ANY)
		require -- from ANY
			other_not_void: other /= Void
			type_identity: same_type (other)
		external
			"built_in"
		ensure -- from ANY
			is_standard_equal: standard_is_equal (other)
		end

	frozen standard_twin: DATE_TIME_CODE_STRING
			-- New object field-by-field identical to other.
			-- Always uses default copying semantics.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			standard_twin_not_void: Result /= Void
			equal: standard_equal (Result, Current)
		end

	frozen twin: DATE_TIME_CODE_STRING
			-- New object equal to Current
			-- twin calls copy; to change copying/twinning semantics, redefine copy.
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			twin_not_void: Result /= Void
			is_equal: Result ~ Current
		end
	
feature -- Basic operations

	frozen as_attached: attached DATE_TIME_CODE_STRING
		obsolete "Remove calls to this feature. [2017-05-31]"
			-- Attached version of Current.
			-- (Can be used during transitional period to convert
			-- non-void-safe classes to void-safe ones.)
			-- (from ANY)
		do
			Result := Current
		end

	frozen default: detachable DATE_TIME_CODE_STRING
			-- Default value of object's type
			-- (from ANY)
		do
		end

	frozen default_pointer: POINTER
			-- Default value of type POINTER
			-- (Avoid the need to write p.default for
			-- some p of type POINTER.)
			-- (from ANY)
		do
		ensure -- from ANY
			instance_free: class
		end

	default_rescue
			-- Process exception for routines with no Rescue clause.
			-- (Default: do nothing.)
			-- (from ANY)
		do
		end

	frozen do_nothing
			-- Execute a null action.
			-- (from ANY)
		do
		ensure -- from ANY
			instance_free: class
		end
	
feature {NONE} -- Implementation

	days: ARRAY [STRING_8]

	extracted_substrings (s: STRING_8; pos1, pos2: INTEGER_32): TUPLE [substrg: STRING_8; substrg2: STRING_8]
			-- Extract substrg and substrg2 from s and specified by the
			-- range pos1..pos2.
			-- (from FIND_SEPARATOR_FACILITY)
		require -- from FIND_SEPARATOR_FACILITY
			string_exists: s /= Void
			range_correct: pos1 <= pos2.abs
		local
			l_substrg, l_substrg2: STRING_8
		do
			if pos2 > 0 then
				l_substrg := s.substring (pos1, pos2 - 1)
				l_substrg2 := s.substring (pos2, pos2)
			else
				l_substrg := s.substring (pos1, - pos2)
				create l_substrg2.make (0)
			end
			Result := [l_substrg, l_substrg2]
		ensure -- from FIND_SEPARATOR_FACILITY
			extracted_substrings_not_void: Result /= Void
			substrings_extracted: Result.substrg /= Void and Result.substrg2 /= Void
		end

	find_separator (s: STRING_8; i: INTEGER_32): INTEGER_32
			-- Position of the next separator in s starting at
			-- i-th character.
			-- ":", "/", "-", ",", " ", "."
			-- (from FIND_SEPARATOR_FACILITY)
		require -- from FIND_SEPARATOR_FACILITY
			s_exists: s /= Void
			i_in_range: 1 <= i and i <= s.count
		local
			j, pos: INTEGER_32
			ch: CHARACTER_8
			sep_found: BOOLEAN
		do
			Result := s.count + 1
			from
				j := 1
			invariant
				inside_bounds: Result >= i and Result <= s.count + 1
			until
				j > Separator_characters.count
			loop
				pos := s.index_of (Separator_characters @ j, 1)
				if pos /= 0 then
					sep_found := True
					pos := s.index_of (Separator_characters @ j, i)
					if pos /= 0 and pos < Result then
						Result := pos
					end
				end
				j := j + 1
			end
			if not sep_found then
				from
					j := i
					if s.substring (j, j + 2).same_string ("[0]") then
						j := j + 3
					end
					ch := s @ j
				until
					j > s.count or else (s @ j) /= ch
				loop
					j := j + 1
					if j <= s.count then
						if ch = 'm' and then (s @ j) = 'i' then
							ch := s @ j
						elseif ch = 'h' and then (s @ j = '1') and (s.valid_index (j + 1) and then s.item (j + 1) = '2') then
							j := j + 1
							ch := s @ j
						end
					end
				end
				Result := (j - 1) * -1
			end
		ensure -- from FIND_SEPARATOR_FACILITY
			not_zero: Result /= 0
		end

	has_separators (s: STRING_8): BOOLEAN
			-- Does date string s contain any separators?
			-- (from FIND_SEPARATOR_FACILITY)
		require -- from FIND_SEPARATOR_FACILITY
			string_exists: s /= Void
		local
			i: INTEGER_32
		do
			from
				i := 1
			until
				i > s.count or Result
			loop
				Result := is_separator (s.substring (i, i))
				i := i + 1
			end
		end

	internal_parser: detachable DATE_TIME_PARSER
			-- Cached instance of date-time string parser

	months: ARRAY [STRING_8]

	parser (s: STRING_8): DATE_TIME_PARSER
			-- Parser from s.
			-- Build a new one if necessary.
		require
			non_empty_string: s /= Void and then not s.is_empty
		do
			Result := internal_parser
			if not attached Result or else not equal (Result.source_string, s) then
				create Result.make (value)
				Result.set_day_array (days)
				Result.set_month_array (months)
				Result.set_base_century (base_century)
				Result.set_source_string (s)
				Result.parse
				internal_parser := Result
			end
		ensure
			parser_not_void: Result /= Void
		end

	right_day_text: BOOLEAN
			-- Is the name of the day the right one?
	
feature -- Attributes

	base_century: INTEGER_32
			-- Base century, used when interpreting 2-digit year
			-- specifications.

	name: STRING_8
			-- Name of the code string.
		local
			i: INTEGER_32
			l_item: detachable DATE_TIME_CODE
		do
			create Result.make (1)
			from
				i := 1
				l_item := value.item (i)
			until
				l_item = Void
			loop
				Result.append (l_item.name)
				Result.append_character (' ')
				i := i + 1
				l_item := value.item (i)
			end
		end

	value: HASH_TABLE [DATE_TIME_CODE, INTEGER_32]
			-- Hash-table representing the code string.
	
feature {NONE} -- Constants

	Separator_characters: STRING_8 = ":/-, ."
			-- (from FIND_SEPARATOR_FACILITY)
	
feature -- Creation

	make (s: STRING_8)
			-- Create code descriptors and hash-table from s.
		require
			s_exists: s /= Void
		local
			i, pos1, pos2: INTEGER_32
			date_constants: DATE_CONSTANTS
			l_substrgs: like extracted_substrings
			l_substrg, l_substrg2: STRING_8
		do
			create value.make (20)
			pos1 := 1
			create date_constants
			days := date_constants.days_text.twin
			months := date_constants.months_text.twin
			from
				i := 1
			until
				pos1 >= s.count
			loop
				pos2 := find_separator (s, pos1)
				l_substrgs := extracted_substrings (s, pos1, pos2)
				pos2 := pos2.abs
				l_substrg := l_substrgs.substrg
				l_substrg.to_lower
				if l_substrg.count > 0 then
					value.put (create {DATE_TIME_CODE}.make (l_substrg), i)
					i := i + 1
				end
				l_substrg2 := l_substrgs.substrg2
				if l_substrg2.count > 0 then
					value.put (create {DATE_TIME_CODE}.make (l_substrg2), i)
					i := i + 1
					separators_used := True
				end
				pos1 := pos2 + 1
			end
			base_century := (create {C_DATE}).year_now // 100 * -100
		ensure
			value_set: value /= Void
			base_century_set: base_century < 0 and (base_century \\ 100 = 0)
		end
	
feature -- Interface

	correspond (s: STRING_8): BOOLEAN
			-- Does the user string s correspond to the code string?
		require
			s_exists: s /= Void
		local
			pos1, pos2, i: INTEGER_32
			code: detachable DATE_TIME_CODE
			has_seps: BOOLEAN
			l_substrgs: like extracted_substrings
			l_substrg, l_substrg2: STRING_8
		do
			pos1 := 1
			if s.is_empty then
				Result := False
			else
				Result := True
				has_seps := has_separators (s)
			end
			from
				i := 1
			until
				pos1 > s.count or not Result
			loop
				code := value.item (i)
				if code = Void then
					Result := False
				else
					if has_seps then
						pos2 := find_separator (s, pos1)
					else
						pos2 := (pos1 + code.count_max - 1) * -1
					end
					l_substrgs := extracted_substrings (s, pos1, pos2)
					pos2 := pos2.abs
					l_substrg := l_substrgs.substrg
					if l_substrg.count > 0 then
						Result := l_substrg.count <= code.count_max and l_substrg.count >= code.count_min
						if code.is_numeric then
							Result := Result and l_substrg.is_integer
							if code.value_max /= -1 and code.value_min /= -1 then
								Result := Result and l_substrg.to_integer <= code.value_max and l_substrg.to_integer >= code.value_min
							end
						elseif code.is_meridiem (code.value) then
							Result := Result and (l_substrg.is_case_insensitive_equal ("AM") or l_substrg.is_case_insensitive_equal ("PM"))
						elseif code.is_day_text (code.value) then
							Result := Result and days.has (l_substrg)
						elseif code.is_month_text (code.value) then
							Result := Result and months.has (l_substrg)
						end
						i := i + 1
					end
					if has_seps then
						code := value.item (i)
						i := i + 1
						if code /= Void then
							l_substrg2 := l_substrgs.substrg2
							Result := Result and pos2 /= s.count and l_substrg2.same_string (code.value)
						end
					end
					pos1 := pos2 + 1
				end
			end
		end

	create_date (s: STRING_8): DATE
			-- Create a DATE according to the format in s.
		require
			s_exists: s /= Void
			is_precise: precise_date
			s_correspond: correspond (s)
		local
			tmp_code: DATE_TIME_CODE
			tmp_ht: HASH_TABLE [DATE_TIME_CODE, INTEGER_32]
			i: INTEGER_32
		do
			tmp_ht := value.twin
			i := value.count + 1
			if has_separators (s) then
				create tmp_code.make (" ")
				value.put (tmp_code, i)
				create tmp_code.make ("hh")
				value.put (tmp_code, i + 1)
				create tmp_code.make (":")
				value.put (tmp_code, i + 2)
				create tmp_code.make ("mi")
				value.put (tmp_code, i + 3)
				create tmp_code.make (":")
				value.put (tmp_code, i + 4)
				create tmp_code.make ("ss")
				value.put (tmp_code, i + 5)
				s.append (" 0:0:0")
				Result := create_date_time (s).date
				s.replace_substring_all (" 0:0:0", "")
			else
				create tmp_code.make ("[0]hh")
				value.put (tmp_code, i)
				create tmp_code.make ("[0]mi")
				value.put (tmp_code, i + 1)
				create tmp_code.make ("[0]ss")
				value.put (tmp_code, i + 2)
				s.append ("000000")
				Result := create_date_time (s).date
				s.remove_tail (6)
			end
			value := tmp_ht
		ensure
			date_exists: Result /= Void
			day_text_equal_day: right_day_text
		end

	create_date_string (date: DATE): STRING_8
			-- Create the output of date according to the code string.
		require
			date_exists: date /= Void
		do
			Result := create_string (create {DATE_TIME}.make_by_date (date))
		ensure
			string_exists: Result /= Void
			string_correspond: correspond (Result)
		end

	create_date_time (s: STRING_8): DATE_TIME
			-- Create DATE_TIME according to s.
		require
			s_exist: s /= Void
			is_precise: precise
			s_correspond: correspond (s)
			valid: is_value_valid (s)
		local
			l_parser: like parser
			l_day_text: detachable STRING_8
		do
			right_day_text := True
			l_parser := parser (s)
			create Result.make_fine (l_parser.year, l_parser.month, l_parser.day, l_parser.hour, l_parser.minute, l_parser.fine_second)
			l_day_text := l_parser.day_text
			if l_day_text /= Void then
				right_day_text := l_day_text.same_string (days.item (Result.date.day_of_the_week))
			end
		ensure
			date_time_exists: Result /= Void
			day_text_equal_day: right_day_text
		end

	create_string (date_time: DATE_TIME): STRING_8
			-- Create the output of date_time according to the code string.
		require
			non_void: date_time /= Void
		local
			date: DATE
			time: TIME
			int, i, type: INTEGER_32
			l_tmp: STRING_8
			l_item: detachable DATE_TIME_CODE
		do
			create Result.make (1)
			date := date_time.date
			time := date_time.time
			from
				i := 1
				l_item := value.item (i)
			until
				l_item = Void
			loop
				type := l_item.type
				inspect type
				when {DATE_TIME_CODE}.day_numeric_type_code then
					Result.append (date.day.out)
				when {DATE_TIME_CODE}.day_numeric_on_2_digits_type_code then
					int := date.day
					if int < 10 then
						Result.append ("0")
					end
					Result.append (int.out)
				when {DATE_TIME_CODE}.day_text_type_code then
					int := date.day_of_the_week
					Result.append (days.item (int))
				when {DATE_TIME_CODE}.year_on_4_digits_type_code then
					l_tmp := date.year.out
					if l_tmp.count = 4 then
						Result.append (l_tmp)
					else
						if l_tmp.count = 1 then
							Result.append ("000")
							Result.append (l_tmp)
						elseif l_tmp.count = 2 then
							Result.append ("00")
							Result.append (l_tmp)
						elseif l_tmp.count = 3 then
							Result.append ("0")
							Result.append (l_tmp)
						end
					end
				when {DATE_TIME_CODE}.year_on_2_digits_type_code then
					l_tmp := date.year.out
					if l_tmp.count > 2 then
						l_tmp.keep_tail (2)
					elseif l_tmp.count = 1 then
						Result.append_character ('0')
					end
					Result.append (l_tmp)
				when {DATE_TIME_CODE}.month_numeric_type_code then
					Result.append (date.month.out)
				when {DATE_TIME_CODE}.month_numeric_on_2_digits_type_code then
					int := date.month
					if int < 10 then
						Result.append ("0")
					end
					Result.append (int.out)
				when {DATE_TIME_CODE}.month_text_type_code then
					int := date.month
					Result.append (months.item (int))
				when {DATE_TIME_CODE}.hour_numeric_type_code then
					Result.append (time.hour.out)
				when {DATE_TIME_CODE}.hour_numeric_on_2_digits_type_code then
					int := time.hour
					if int < 10 then
						Result.append ("0")
					end
					Result.append (int.out)
				when {DATE_TIME_CODE}.hour_12_clock_scale_type_code, {DATE_TIME_CODE}.hour_12_clock_scale_on_2_digits_type_code then
					int := time.hour
					if int < 12 then
						if int = 0 then
							int := 12
						end
					else
						if int /= 12 then
							int := int - 12
						end
					end
					if type = {DATE_TIME_CODE}.hour_12_clock_scale_on_2_digits_type_code.to_integer_32 and then int < 10 then
						Result.append ("0")
					end
					Result.append (int.out)
				when {DATE_TIME_CODE}.minute_numeric_type_code then
					Result.append (time.minute.out)
				when {DATE_TIME_CODE}.minute_numeric_on_2_digits_type_code then
					int := time.minute
					if int < 10 then
						Result.append ("0")
					end
					Result.append (int.out)
				when {DATE_TIME_CODE}.second_numeric_type_code then
					Result.append (time.second.out)
				when {DATE_TIME_CODE}.second_numeric_on_2_digits_type_code then
					int := time.second
					if int < 10 then
						Result.append ("0")
					end
					Result.append (int.out)
				when {DATE_TIME_CODE}.fractional_second_numeric_type_code then
					int := (time.fractional_second * 10 ^ l_item.count_max.to_double).rounded
					l_tmp := int.out
					if l_tmp.count < l_item.count_max then
						Result.append (create {STRING_8}.make_filled ('0', l_item.count_max - l_tmp.count))
					end
					Result.append (l_tmp)
				when {DATE_TIME_CODE}.meridiem_type_code then
					int := time.hour
					if int < 12 then
						Result.append ("AM")
					else
						Result.append ("PM")
					end
				else
					Result.append (l_item.value)
				end
				i := i + 1
				l_item := value.item (i)
			end
		ensure
			string_exists: Result /= Void
			string_correspond: correspond (Result)
		end

	create_time (s: STRING_8): TIME
			-- Create a TIME according to the format in s.
		require
			s_exists: s /= Void
			is_precise: precise_time
			s_correspond: correspond (s)
		local
			tmp_code: DATE_TIME_CODE
			tmp_ht: HASH_TABLE [DATE_TIME_CODE, INTEGER_32]
			i: INTEGER_32
		do
			tmp_ht := value.twin
			i := value.count + 1
			if has_separators (s) then
				create tmp_code.make (" ")
				value.put (tmp_code, i)
				create tmp_code.make ("dd")
				value.put (tmp_code, i + 1)
				create tmp_code.make ("/")
				value.put (tmp_code, i + 2)
				create tmp_code.make ("mm")
				value.put (tmp_code, i + 3)
				create tmp_code.make ("/")
				value.put (tmp_code, i + 4)
				create tmp_code.make ("yy")
				value.put (tmp_code, i + 5)
				s.append (" 1/1/01")
				Result := create_date_time (s).time
				s.replace_substring_all (" 1/1/01", "")
			else
				create tmp_code.make ("[0]dd")
				value.put (tmp_code, i)
				create tmp_code.make ("[0]mm")
				value.put (tmp_code, i + 1)
				create tmp_code.make ("yy")
				value.put (tmp_code, i + 2)
				s.append ("010101")
				Result := create_date_time (s).time
				s.remove_tail (6)
			end
			value := tmp_ht
		ensure
			time_exists: Result /= Void
			time_correspond: create_time_string (Result).same_string (s)
		end

	create_time_string (time: TIME): STRING_8
			-- Create the output of time according to the code string.
		require
			time_exists: time /= Void
		local
			date_time: DATE_TIME
		do
			create date_time.make_fine (1, 1, 1, time.hour, time.minute, time.fine_second)
			Result := create_string (date_time)
		ensure
			string_exists: Result /= Void
			string_correspond: correspond (Result)
		end

	precise: BOOLEAN
			-- Is the code string enough precise to create
			-- nn instance of type DATE_TIME?
		require
			not_void: value /= Void
		do
			Result := precise_date and precise_time
		end

	precise_date: BOOLEAN
			-- Is the code string enough precise to create
			-- nn instance of type DATE?
		require
			not_void: value /= Void
		local
			i, type: INTEGER_32
			has_day, has_month, has_year: BOOLEAN
		do
			from
				i := 1
			until
				not attached value.item (i) as l_item
			loop
				type := l_item.type
				if separators_used then
					inspect type
					when {DATE_TIME_CODE}.day_numeric_type_code, {DATE_TIME_CODE}.day_numeric_on_2_digits_type_code then
						has_day := True
					when {DATE_TIME_CODE}.year_on_4_digits_type_code, {DATE_TIME_CODE}.year_on_2_digits_type_code then
						has_year := True
					when {DATE_TIME_CODE}.month_numeric_type_code, {DATE_TIME_CODE}.month_numeric_on_2_digits_type_code, {DATE_TIME_CODE}.month_text_type_code then
						has_month := True
					else
					end
				else
					inspect type
					when {DATE_TIME_CODE}.day_numeric_on_2_digits_type_code then
						has_day := True
					when {DATE_TIME_CODE}.year_on_4_digits_type_code, {DATE_TIME_CODE}.year_on_2_digits_type_code then
						has_year := True
					when {DATE_TIME_CODE}.month_numeric_on_2_digits_type_code then
						has_month := True
					else
					end
				end
				i := i + 1
			end
			Result := has_day and has_month and has_year
		end

	precise_time: BOOLEAN
			-- Is the code string enough precise to create
			-- an instance of type TIME?
		require
			not_void: value /= Void
		local
			i, type: INTEGER_32
			has_hour_12, has_hour_24, has_minute, has_second: BOOLEAN
		do
			from
				i := 1
			until
				not attached value.item (i) as l_item
			loop
				type := l_item.type
				if separators_used then
					inspect type
					when {DATE_TIME_CODE}.hour_numeric_type_code, {DATE_TIME_CODE}.hour_numeric_on_2_digits_type_code then
						has_hour_24 := True
					when {DATE_TIME_CODE}.minute_numeric_type_code, {DATE_TIME_CODE}.minute_numeric_on_2_digits_type_code then
						has_minute := True
					when {DATE_TIME_CODE}.second_numeric_type_code, {DATE_TIME_CODE}.second_numeric_on_2_digits_type_code then
						has_second := True
					when {DATE_TIME_CODE}.hour_12_clock_scale_type_code, {DATE_TIME_CODE}.hour_12_clock_scale_on_2_digits_type_code then
						has_hour_12 := True
					else
					end
				else
					inspect type
					when {DATE_TIME_CODE}.hour_numeric_on_2_digits_type_code then
						has_hour_24 := True
					when {DATE_TIME_CODE}.minute_numeric_on_2_digits_type_code then
						has_minute := True
					when {DATE_TIME_CODE}.second_numeric_on_2_digits_type_code then
						has_second := True
					when {DATE_TIME_CODE}.hour_12_clock_scale_on_2_digits_type_code then
						has_hour_12 := True
					else
					end
				end
				i := i + 1
			end
			Result := (has_hour_24 or has_hour_12) and has_minute and has_second
		end
	
feature -- Output

	Io: STD_FILES
			-- Handle to standard file setup
			-- (from ANY)
		once
			create Result
			Result.set_output_default
		ensure -- from ANY
			instance_free: class
			io_not_void: Result /= Void
		end

	out: STRING_8
			-- New string containing terse printable representation
			-- of current object
			-- (from ANY)
		do
			Result := tagged_out
		ensure -- from ANY
			out_not_void: Result /= Void
		end

	print (o: detachable ANY)
			-- Write terse external representation of o
			-- on standard output.
			-- (from ANY)
		do
			if o /= Void then
				Io.put_string (o.out)
			end
		ensure -- from ANY
			instance_free: class
		end

	frozen tagged_out: STRING_8
			-- New string containing terse printable representation
			-- of current object
			-- (from ANY)
		external
			"built_in"
		ensure -- from ANY
			tagged_out_not_void: Result /= Void
		end
	
feature -- Platform

	Operating_environment: OPERATING_ENVIRONMENT
			-- Objects available from the operating system
			-- (from ANY)
		once
			create Result
		ensure -- from ANY
			instance_free: class
			operating_environment_not_void: Result /= Void
		end
	
feature {NONE} -- Preconditions

	is_code (s: STRING_8): BOOLEAN
			-- Is the string a code?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := is_colon (s) or is_comma (s) or is_day (s) or is_day0 (s) or is_day_text (s) or is_dot (s) or is_fractional_second (s) or is_hour (s) or is_hour0 (s) or is_hour12 (s) or is_hour12_0 (s) or is_meridiem (s) or is_minus (s) or is_minute (s) or is_minute0 (s) or is_month (s) or is_month0 (s) or is_month_text (s) or is_second (s) or is_second0 (s) or is_slash (s) or is_space (s) or is_year2 (s) or is_year4 (s)
		end

	is_colon (s: STRING_8): BOOLEAN
			-- Is the code a separator-colomn?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string (":")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string (":")
		end

	is_comma (s: STRING_8): BOOLEAN
			-- Is the code a separator-coma?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string (",")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string (",")
		end

	is_day (s: STRING_8): BOOLEAN
			-- Is the code a day-numeric?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("dd")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("dd")
		end

	is_day0 (s: STRING_8): BOOLEAN
			-- Is the code a day-numeric
			-- Padded with zero?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("[0]dd")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("[0]dd")
		end

	is_day_text (s: STRING_8): BOOLEAN
			-- Is the code a day-text?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("ddd")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("ddd")
		end

	is_dot (s: STRING_8): BOOLEAN
			-- Is the code a separator-dot?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string (".")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string (".")
		end

	is_fractional_second (s: STRING_8): BOOLEAN
			-- Is the code a fractional-second
			-- With precision to n figures?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			if s.count > 2 then
				Result := s.substring (1, 2).same_string ("ff") and s.substring (3, s.count).is_integer
			end
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = (s.count > 2 and then (s.substring (1, 2).same_string ("ff") and s.substring (3, s.count).is_integer))
		end

	is_hour (s: STRING_8): BOOLEAN
			-- Is the code a 24-hour-clock-scale?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("hh")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("hh")
		end

	is_hour0 (s: STRING_8): BOOLEAN
			-- Is the code a 24-hour-clock-scale
			-- Padded with zero?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("[0]hh")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("[0]hh")
		end

	is_hour12 (s: STRING_8): BOOLEAN
			-- Is the code a 12-hour-clock-scale?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("hh12")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("hh12")
		end

	is_hour12_0 (s: STRING_8): BOOLEAN
			-- Is the code a 12-hour-clock-scale padded with zero?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("[0]hh12")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("[0]hh12")
		end

	is_meridiem (s: STRING_8): BOOLEAN
			-- Is the code a meridiem notation?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		local
			tmp: STRING_8
		do
			tmp := s.as_upper
			Result := tmp.same_string ("AM") or tmp.same_string ("PM")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.as_upper.same_string ("AM") or s.as_upper.same_string ("PM")
		end

	is_minus (s: STRING_8): BOOLEAN
			-- Is the code a separator-minus?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("-")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("-")
		end

	is_minute (s: STRING_8): BOOLEAN
			-- Is the code a minute-numeric?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("mi")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("mi")
		end

	is_minute0 (s: STRING_8): BOOLEAN
			-- Is the code a minute-numeric
			-- Padded with zero?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("[0]mi")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("[0]mi")
		end

	is_month (s: STRING_8): BOOLEAN
			-- Is the code a month-numeric?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("mm")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("mm")
		end

	is_month0 (s: STRING_8): BOOLEAN
			-- Is the code a month-numeric
			-- Padded with zero?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("[0]mm")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("[0]mm")
		end

	is_month_text (s: STRING_8): BOOLEAN
			-- Is the code a month-text?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("mmm")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("mmm")
		end

	is_second (s: STRING_8): BOOLEAN
			-- Is the code a second-numeric?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("ss")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("ss")
		end

	is_second0 (s: STRING_8): BOOLEAN
			-- Is the code a second-numeric
			-- Padded with zero?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("[0]ss")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("[0]ss")
		end

	is_separator (s: STRING_8): BOOLEAN
			-- Is the code a separator?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := is_slash (s) or else is_colon (s) or else is_minus (s) or else is_comma (s) or else is_space (s) or else is_dot (s)
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = is_slash (s) or else is_colon (s) or else is_minus (s) or else is_comma (s) or else is_space (s) or else is_dot (s)
		end

	is_slash (s: STRING_8): BOOLEAN
			-- Is the code a separator-slash?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("/")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("/")
		end

	is_space (s: STRING_8): BOOLEAN
			-- Is the code a separator-space?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string (" ")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string (" ")
		end

	is_year2 (s: STRING_8): BOOLEAN
			-- Is the code a year-numeric
			-- On 2 figures?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("yy")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("yy")
		end

	is_year4 (s: STRING_8): BOOLEAN
			-- Is the code a year-numeric
			-- On 4 figures?
			-- (from CODE_VALIDITY_CHECKER)
		require -- from CODE_VALIDITY_CHECKER
			s_exists: s /= Void
		do
			Result := s.same_string ("yyyy")
		ensure -- from CODE_VALIDITY_CHECKER
			definition: Result = s.same_string ("yyyy")
		end
	
feature {NONE} -- Retrieval

	frozen internal_correct_mismatch
			-- Called from runtime to perform a proper dynamic dispatch on correct_mismatch
			-- from MISMATCH_CORRECTOR.
			-- (from ANY)
		local
			l_msg: STRING_8
			l_exc: EXCEPTIONS
		do
			if attached {MISMATCH_CORRECTOR} Current as l_corrector then
				l_corrector.correct_mismatch
			else
				create l_msg.make_from_string ("Mismatch: ")
				create l_exc
				l_msg.append (generating_type.name)
				l_exc.raise_retrieval_exception (l_msg)
			end
		end
	
invariant
		-- from ANY
	reflexive_equality: standard_is_equal (Current)
	reflexive_conformance: conforms_to (Current)

note
	copyright: "Copyright (c) 1984-2018, 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_CODE_STRING

Generated by ISE EiffelStudio