diff --git a/jj_temporal b/jj_temporal deleted file mode 160000 index 8b8f6b7..0000000 --- a/jj_temporal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8b8f6b7b3b39f254293920f4e5f0fb1ab5c1926b diff --git a/jj_temporal/README.md b/jj_temporal/README.md new file mode 100644 index 0000000..d69b0e4 --- /dev/null +++ b/jj_temporal/README.md @@ -0,0 +1,7 @@ +# jj_temporal +Eiffel date and time classes + +Main classes: ![](docs/main_classes.png?raw=true) + + + diff --git a/jj_temporal/classes/abstract_duration.e b/jj_temporal/classes/abstract_duration.e new file mode 100644 index 0000000..df14a88 --- /dev/null +++ b/jj_temporal/classes/abstract_duration.e @@ -0,0 +1,229 @@ +note + description: "[ + Notion of a duration of time such as 2 hours, or 3 years, etc. + ]" + names: "abstract_duration, duration" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + ABSTRACT_DURATION + +inherit + COMPARABLE + +feature -- Access + +feature -- Access + + as_string: STRING + -- The time represented as a string, ideally with not extra characters. + deferred + end + + negative: like Current + -- The negative value of this duration + do + Result := twin + Result.negate + ensure + negative_result: Current > zero implies Result < zero + positive_result: Current < zero implies Result > zero + end + + one: like Current + -- Neutral element for "*" and "/" + deferred + ensure + result_exists: Result /= Void + valid_result: Result.is_one + end + + zero: like Current + -- Neutral element for "+" and "-" + deferred + ensure + result_exists: Result /= Void + good_result: Result.is_zero + end + +feature -- Status Report + + is_zero: BOOLEAN + -- Is this duration of 0 length? + do + Result := equal (Current, zero) + ensure + valid_result: Result implies equal (Current, zero) + end + + is_one: BOOLEAN + -- Is this duration neutral for '*' and '/'? + do + Result := equal (Current, one) + ensure + valid_result: Result implies equal (Current, one) + end + + is_negative: BOOLEAN + -- Is current less than the 'zero' duration? + do + Result := Current < zero + ensure + valid_result: Result implies Current < zero + end + +feature -- Element Change + + set_zero + -- Make the duration have zero length. + deferred + ensure + is_zero: is_zero + end + + + negate + -- Reverses the sign. + deferred + ensure + positive_implication: not is_negative implies old is_negative + negative_implication: is_negative implies not old is_negative + end + + add (other: like Current) + -- Add other other to Current. + require + other_exists: other /= Void + deferred + end + + sub (other: like Current) + -- Subtract other from Current + require + other_exists: other /= Void + deferred + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + deferred + end + + divide (r: DOUBLE) + -- Divide by 'r'. + require + not_zero_devisor: r /= 0 + deferred + end + + div (i: INTEGER) + -- Integer division. + require + not_zero_devisor: i /= 0 + deferred + end + + mod (i: INTEGER) + -- Modulo. + require + not_zero_devisor: i /= 0 + deferred + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + -- For example: is current duration at least twice as long as other? + require + other_exists: other /= Void + other_not_zero: not other.is_zero + deferred + end + +feature -- Basic operations + + identity alias "+": like Current + -- Just a clone of Current. Included for symetry. + do + Result := twin + ensure + no_side_effect: equal (Current, old Current) + end + + oposite alias "-": like Current + -- Invert the sign of other. + do + Result := twin + Result.negate + ensure + no_side_effect: equal (Current, old Current) + end + + plus alias "+" (other: like Current): like Current + -- Sum of current and other. + do + Result := twin + Result.add (other) + ensure + no_side_effect: equal (Current, old Current) + end + + minus alias "-" (other: like Current): like Current + -- Difference of Current and other. + do + Result := twin + Result.sub (other) + ensure + no_side_effect: equal (Current, old Current) + end + + product alias "*" (r: DOUBLE): like Current + -- Product of Current and 'r'. + -- Multiply by a factor of 'r'. + do + Result := twin + Result.multiply (r) + ensure + no_side_effect: equal (Current, old Current) + end + + quotient alias "/" (r: DOUBLE): like Current + -- Quotent of Current by 'r'. + require + not_zero_devisor: r /= 0 + do + Result := twin + Result.divide (r) + ensure + no_side_effect: equal (Current, old Current) + end + + integer_quotient alias "//" (i: INTEGER): like Current + -- Integer division of Current by 'i'. + require + not_zero_devisor: i /= 0 + do + Result := twin + Result.div (i) + ensure + no_side_effect: equal (Current, old Current) + end + + integer_remainder alias "\\" (i: INTEGER): like Current + -- Modulo of Current by 'i'. + require + not_zero_devisor: i /= 0 + do + Result := twin + Result.mod (i) + ensure + no_side_effect: equal (Current, old Current) + end + +end + diff --git a/jj_temporal/classes/abstract_interval.e b/jj_temporal/classes/abstract_interval.e new file mode 100644 index 0000000..82c074c --- /dev/null +++ b/jj_temporal/classes/abstract_interval.e @@ -0,0 +1,387 @@ +note + description: "[ + Notion of a span of time consisting of a start-time, a + finish-time and a duration. Positive durations only. + ]" + names: "abstract_interval, time_span, time_interval, span" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + ABSTRACT_INTERVAL + +inherit + + COMPARABLE + undefine + default_create + end + +feature -- Access + + start: like time_anchor + -- Beginning moment of the time span and anchor for class. + do + Result := start_imp.twin + ensure + result_exists: Result /= Void + end + + finish: like time_anchor + -- Ending moment of the time span. + do + Result := finish_imp.twin + ensure + result_exists: Result /= Void + end + + duration: like duration_anchor + -- Length of time span. + do + Result := finish.time_between (start) + ensure + result_exists: Result /= Void + end + +feature -- Element Change + + set_start_finish (a_start_time, a_finish_time: like time_anchor) + -- Set the `start' and `finish' times. + require + times_exists: a_start_time /= Void and a_finish_time /= Void + valid_times: a_start_time <= a_finish_time + do + start_imp := a_start_time.twin + finish_imp := a_finish_time.twin + ensure + start_was_set: equal (start, a_start_time) + finish_was_set: equal (finish, a_finish_time) + end + + set_start_duration (a_start_time: like time_anchor; a_duration: like duration_anchor) + -- Set the `start' time and the `duration'. + require + start_time_exists: a_start_time /= Void + duration_exists: a_duration /= Void + positive_duration: not a_duration.is_negative + do + start_imp := a_start_time.twin + finish_imp := a_start_time + a_duration + ensure + start_was_set: equal (start, a_start_time) + duration_was_set: equal (duration, a_duration) + end + + set_duration_finish (a_duration: like duration_anchor; a_finish_time: like time_anchor) + -- Set the `duration' and `finish' time. + require + duration_exists: a_duration /= Void + positive_duration: not a_duration.is_negative + finish_time_exists: a_finish_time /= Void + do + start_imp := a_finish_time - a_duration + finish_imp := a_finish_time.twin + ensure + finish_was_set: equal (finish, a_finish_time) + duration_was_set: equal (duration, a_duration) + end + + move (a_duration: like duration_anchor) + -- Change the `start' and `finish' times by moving the + -- interval by the amount represented by `a_duration'. + require + duration_exists: a_duration /= Void + do + start_imp.add_duration (a_duration) + finish_imp.add_duration (a_duration) + ensure + duration_unchanged: equal (duration, old duration) + end + +feature -- Status Report + + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does current interval start before other or if they start at the + -- same time, does Current end before the other? + do + if (start < other.start) or else + (start.is_equal (other.start) and then finish < other.finish) then + Result := true + end + ensure then + less_than_definition: Result implies (start < other.start or else + (start.is_equal (other.start) and then finish < other.finish)) + end + + meets (other: like Current): BOOLEAN + -- x.meets(y) |-----x----->| + -- y.is_met_by(x) |-----y----->| + require + other_exists: other /= Void + do + Result := equal (finish, other.start) + ensure + Result implies equal (finish, other.start) + Result implies Current < other + end + + is_met_by (other: like Current): BOOLEAN + -- x.meets(y) |-----x----->| + -- y.is_met_by(x) |-----y----->| + require + other_exists: other /= Void + do + Result := equal (start, other.finish) + ensure + Result implies equal (start, other.finish) + Result implies other < Current + end + + is_before (other: like Current): BOOLEAN + -- x.is_before(y) |-----x----->| + -- y.is_after(x) |-----y----->| + require + other_exists: other /= Void + do + Result := finish < other.start + ensure + Result implies finish.is_before (other) + Result implies Current < other + end + + is_after (other: like Current): BOOLEAN + -- x.is_before(y) |-----x----->| + -- y.is_after(x) |-----y----->| + require + other_exists: other /= Void + do + Result := start > other.finish + ensure + Result implies start.is_after (other) + Result implies other < Current + end + + includes (other: like Current): BOOLEAN + -- x.includes(y) |-----x----->| + -- y.is_included_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := other.start.belongs (Current) and + other.finish.belongs (Current) + ensure + Result implies other.start.belongs (Current); + Result implies other.finish.belongs (Current) + end + + is_included_by (other: like Current): BOOLEAN + -- x.includes(y) |-----x----->| + -- y.is_included_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := start.belongs (other) and finish.belongs (other) + ensure + Result implies start.belongs (other); + Result implies finish.belongs (other); + end + + overlaps (other: like Current): BOOLEAN + -- x.overlaps(y) |-----x----->| + -- y.is_overlapped_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := finish.belongs (other) + ensure + Result implies finish.belongs (other) + end + + is_overlapped_by (other: like Current): BOOLEAN + -- x.overlaps(y) |-----x----->| + -- y.is_overlapped_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := other.finish.belongs (Current) + ensure + Result implies other.finish.belongs (Current) + end + + intersects (other: like Current): BOOLEAN + -- Do the two intervals have a least one time point in common? + require + other_exists: other /= Void + do + Result := meets (other) or is_met_by (other) or else + includes (other) or is_included_by (other) or else + overlaps (other) or is_overlapped_by (other) + ensure + Result implies meets (other) or is_met_by (other) or else + includes (other) or is_included_by (other) or else + overlaps (other) or is_overlapped_by (other) + end + +feature -- Transformation + + unite (other: like Current) + -- Transform into the union between this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |------------x.union(y)----------->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + local + temp_start: like time_anchor + temp_finish: like finish + do + temp_start := start.min (other.start) + temp_finish := finish.max (other.finish) + set_start_finish (temp_start, temp_finish); + ensure + valid_result: equal (start, old start.min(other.start)) and + equal (finish, old finish.max(other.finish)) + end + + intersect (other: like Current) + -- Transform into the intersection of this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |--x.intersection(y)-->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + local + temp_start: like time_anchor + temp_finish: like finish + do + temp_start := start.max (other.start) + temp_finish := finish.min (other.finish) + set_start_finish (temp_start, temp_finish); + ensure + valid_result: equal (start, old start.max(other.start)) and + equal (finish, old finish.min(other.finish)) + end + + split (a_time: like time_anchor): like Current + -- Transform by splitting the interval at 'a_time'. + -- Result is the interval after 'a_time'. + -- | + -- time + -- | + -- V + -- |-----Current----------------->| + -- |---Current--->|----Result---->| + -- Only valid if time is within the interval. + require + time_exists: a_time /= Void + time_in_interval: a_time.belongs (Current) + do + Result := twin + set_start_finish (start, a_time) + Result.set_start_finish (a_time, Result.finish) + ensure + closure: equal (old Current, Result.union (Current)) + meets_result: Current.meets (Result) + end + +feature -- Basic operations + + union (other: like Current): like Current + -- The union between this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |------------x.union(y)----------->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + do + Result := twin + Result.unite (other) + ensure + no_side_effect: equal (Current, old Current) + valid_result: equal (Result.start, start.min(other.start)) and + equal (Result.finish, finish.max(other.finish)) + end + + intersection (other: like Current): like Current + -- The intersection of this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |--x.intersection(y)-->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + do + Result := twin + Result.intersect (other) + ensure + no_side_effect: equal (Current, old Current) + valid_result: equal (Result.start, start.max (other.start)) and + equal (Result.finish, finish.min(other.finish)) + end + + time_at_percent (a_ratio: DOUBLE): like time_anchor + -- Time based on some percentage of this interval. + -- Example 1: if 'a_ratio' is 0.0 then result = 'start'; if + -- 'a_ratio' is 0.5 then resulting time is 1/2 the distance + -- from start to finish; if 'a_ratio' is 2.0 then resulting time + -- is at twice the duration from start to finish. + do + Result := start + (duration * a_ratio) + end + +feature {NONE} -- Implementation + + start_imp: like time_anchor + -- Used internally to prevent changes to `start' which could otherwise + -- be induced by calls to a _TIME. + + finish_imp: like time_anchor + -- Used internally to prevent changes to `finish' which could otherwise + -- be induced by calls to a _TIME. + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: ABSTRACT_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: ABSTRACT_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +invariant + + is_initialized: start_imp /= Void and finish_imp /= Void + start_before_finish: start <= finish + positive_duration: not duration.is_negative + +end diff --git a/jj_temporal/classes/abstract_time.e b/jj_temporal/classes/abstract_time.e new file mode 100644 index 0000000..11899dd --- /dev/null +++ b/jj_temporal/classes/abstract_time.e @@ -0,0 +1,273 @@ +note + description: "[ + Notion of a time, such as <1 Jan 98> or <10:30 P.M.> or , etc. + ]" + names: "abstract_time, time, date" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + ABSTRACT_TIME + +inherit + COMPARABLE + +feature -- Access + + as_string: STRING + -- The time represented as a string, ideally with not extra characters. + deferred + end + + as_integer: INTEGER + -- The time as represented by an INTEGER. + require + is_representable: is_representable_as_integer + deferred + end + +feature -- Initialization + + set_now + -- Set current time according to timezone. + deferred + end + + set_now_utc + -- Set the current object to today's date in utc format. + deferred + end + + set_now_utc_fine + -- Set the current object to today's date in utc format. + deferred + end + +feature -- Element change + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + require + valid_string_representation: is_valid_string_representation (a_string) + deferred + end + + from_integer (a_integer: INTEGER) + -- Change Current to the time represented by `a_integer'. + require + valid_integer_representation: is_valid_integer_representation (a_integer) + deferred + end + + add_duration (a_duration: like duration_anchor) + -- adds a duration to Current time + require + duration_exists: a_duration /= Void + deferred + end + +feature -- Basic operations + + plus alias "+" (a_duration: like duration_anchor): like Current + -- same as add_duration except returns a new time + require + duration_exists: a_duration /= Void + do + Result := twin + Result.add_duration (a_duration) + ensure + no_side_effect: equal (Current, old Current) + end + + minus alias "-" (a_duration: like duration_anchor): like Current + -- same as adding a negative duration except returns a new time + require + duration_exists: a_duration /= Void + do + Result := twin + Result.add_duration (a_duration.negative) + ensure + no_side_effect: equal (Current, old Current) + end + +feature -- Status report + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + deferred + end + +feature -- Querry + + is_before (a_interval: like interval_anchor): BOOLEAN + -- Is this time before the interval? + require + interval_exists: a_interval /= Void + do + Result := Current < a_interval.start + ensure + valid_result: Result implies Current < a_interval.start + end + + is_after (a_interval: like interval_anchor): BOOLEAN + -- Is this time after the interval? + require + interval_exists: a_interval /= Void + do + Result := Current > a_interval.finish + ensure + valid_result: Result implies Current > a_interval.finish + end + + belongs (a_interval: like interval_anchor): BOOLEAN + -- Does this time fall somewhere during the interval? + require + interval_exists: a_interval /= Void + do + Result := Current >= a_interval.start and Current <= a_interval.finish + ensure + valid_result: Result implies Current >= a_interval.start and Current <= a_interval.finish + end + + is_between (time_1, time_2: like Current): BOOLEAN + -- Is current between the two times? + require + others_exist: time_1 /= Void and time_2 /= Void + do + if time_1 < Current and Current < time_2 then + Result := True + elseif time_2 < Current and Current < time_1 then + Result := True + end + ensure + valid_result: Result implies ((time_1 < Current and Current < time_2) or else + (time_2 < Current and Current < time_1)) + end + + is_between_inclusive (time_1, time_2: like Current): BOOLEAN + -- Is current between the two times or equal to one of the two times? + require + others_exist: time_1 /= Void and time_2 /= Void + do + if time_1 <= Current and Current <= time_2 then + Result := True + elseif time_2 <= Current and Current <= time_1 then + Result := True + end + ensure + valid_result: Result implies ((time_1 <= Current and Current <= time_2) or else + (time_2 <= Current and Current <= time_1)) + end + + percent_of (a_interval: like interval_anchor): DOUBLE + -- Where does this time fall in relation to the interval? + -- If current time is before the interval then result should be negative. + -- If current time is after the interval then result should be > 1 (i.e. > 100%). + -- If current time belongs to the interval then result should be between 0 and 1. + require + interval_exists: a_interval /= Void + local + int: like Interval_anchor + do +-- int := twin (a_interval) + int := a_interval.deep_twin + if is_before (a_interval) then + int.set_start_finish (Current, a_interval.start) + if not a_interval.duration.is_zero then + Result := -(int.duration.percent_of (a_interval.duration)) + end + else + int.set_start_finish (a_interval.start, Current) + if not a_interval.duration.is_zero then + Result := int.duration.percent_of (a_interval.duration) + end + end + ensure + negative_if_before: Result < 0 implies Current.is_before (a_interval) + zero_to_one_if_belongs: (Result >= 0 and Result <= 1) implies Current.belongs (a_interval) + over_one_if_after: Result > 1 implies Current.is_after (a_interval) + end + + time_between (other: like Current): like duration_anchor + -- The duration of time between Current and other + require + other_exists: other /= Void + deferred + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + deferred + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in the range reconizable by Current? + deferred + end + +feature {NONE} -- Implementation + + C_date: C_DATE + -- Used to set the date and time based on system clock. + once + create Result + end + + is_valid: BOOLEAN + -- Test used by invariant. + do + Result := True + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: ABSTRACT_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: ABSTRACT_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +invariant + + always_valid: is_valid + +note + copyright: "Copyright (c) 1984-2015, 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 + + + diff --git a/jj_temporal/classes/c_date.e b/jj_temporal/classes/c_date.e new file mode 100644 index 0000000..e05ce51 --- /dev/null +++ b/jj_temporal/classes/c_date.e @@ -0,0 +1,255 @@ +note + description: "Representation of a date at C level" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date: 2014-03-11 23:16:07 -0400 (Tue, 11 Mar 2014) $" + revision: "$Revision: 35 $" + +class + C_DATE + + -- This is a copy of C_DATE from ISE's time cluster. I copied + -- it to my support cluster so I can use it in my temporal and + -- other projects without the overhead of using all of ISE's + -- time cluster. + +inherit + ANY + redefine + default_create + end + +create + default_create, + make_utc + +feature {NONE} -- Initialization + + default_create + -- Create an instance of C_DATA using current local time. + do + is_utc := False + update + end + + make_utc + -- Create an instance of C_DATE holding UTC values. + do + is_utc := True + update + ensure + is_utc: is_utc + end + +feature -- Access + + is_utc: BOOLEAN + -- Is Current holding value in UTC format? + +feature -- Update + + update + -- Pointer to `struct tm' area. + local + l_timeb, l_tm, l_time: POINTER + l_milli: INTEGER + do + l_timeb := l_timeb.memory_alloc (timeb_structure_size) + l_time := l_time.memory_alloc (time_t_structure_size) + ftime (l_timeb) + get_time (l_timeb, l_time) + if is_utc then + l_tm := gmtime (l_time) + else + l_tm := localtime (l_time) + end + create internal_item.make_from_pointer (l_tm, tm_structure_size) + + l_milli := get_millitm (l_timeb) + if l_milli < 0 or l_milli > 999 then + millisecond_now := 0 + else + millisecond_now := l_milli + end + + l_timeb.memory_free + l_time.memory_free + end + +feature -- Status + + year_now: INTEGER + -- Current year at creation time or after last call to `update'. + do + Result := 1900 + get_tm_year (internal_item.item) + ensure + year_valid: Result >= 1900 + end + + month_now: INTEGER + -- Current month at creation time or after last call to `update'. + do + Result := get_tm_mon (internal_item.item) + 1 + ensure + month_valid: Result >= 1 and Result <= 12 + end + + day_now: INTEGER + -- Current day at creation time or after last call to `update'. + do + Result := get_tm_mday (internal_item.item) + ensure + day_valid: Result >= 1 and Result <= 31 + end + + hour_now: INTEGER + -- Current hour at creation time or after last call to `update'. + do + Result := get_tm_hour (internal_item.item) + ensure + hour_valid: Result >= 0 and Result <= 23 + end + + minute_now: INTEGER + -- Current minute at creation time or after last call to `update'. + do + Result := get_tm_min (internal_item.item) + ensure + minute_valid: Result >= 0 and Result <= 59 + end + + second_now: INTEGER + -- Current second at creation time or after last call to `update'. + do + Result := get_tm_sec (internal_item.item) + if Result > 59 then + -- Some platform returns up to 61 for leap seconds. + Result := 59 + end + ensure + second_valid: Result >= 0 and Result <= 59 + end + + millisecond_now: INTEGER + -- Current millisecond at creation time or after last call to `update'. + +feature {NONE} -- Externals + + ftime (p: POINTER) + -- Set current date and time in `p', pointer to a `struct timeb' area. + external + "C macro signature (struct timeb*) use " + end + +feature {NONE} -- `struct timeb' encapsulation + + timeb_structure_size: INTEGER + -- Size of `struct timeb'. + external + "C macro use " + alias + "sizeof(struct timeb)" + end + + time_t_structure_size: INTEGER + -- Size of `struct timeb'. + external + "C macro use " + alias + "sizeof(time_t)" + end + + tm_structure_size: INTEGER + -- Size of `struct tm'. + external + "C macro use " + alias + "sizeof(struct tm)" + end + + get_millitm (p: POINTER): INTEGER + -- Get `p->millitm'. + external + "C struct struct timeb access millitm use " + end + + get_time (p, t: POINTER) + -- Get `p->time'. + external + "C inline use , " + alias + "*(time_t *) $t = (((struct timeb *)$p)->time);" + end + +feature {NONE} -- `struct tm' encapsulation + + internal_item: MANAGED_POINTER + -- Pointer to `struct tm' area. + + localtime (t: POINTER): POINTER + -- Pointer to `struct tm' area. + external + "C inline use " + alias + "localtime ((time_t *) $t)" + end + + gmtime (t: POINTER): POINTER + -- Pointer to `struct tm' area in UTC. + external + "C inline use " + alias + "gmtime ((time_t *) $t)" + end + + get_tm_year (p: POINTER): INTEGER + -- Get `p->tm_year', number of years since 1900. + external + "C struct struct tm access tm_year use " + end + + get_tm_mon (p: POINTER): INTEGER + -- Get `p->tm_mon'. + external + "C struct struct tm access tm_mon use " + end + + get_tm_mday (p: POINTER): INTEGER + -- Get `p->tm_mday'. + external + "C struct struct tm access tm_mday use " + end + + get_tm_hour (p: POINTER): INTEGER + -- Get `p->tm_hour'. + external + "C struct struct tm access tm_hour use " + end + + get_tm_min (p: POINTER): INTEGER + -- Get `p->tm_min'. + external + "C struct struct tm access tm_min use " + end + + get_tm_sec (p: POINTER): INTEGER + -- Get `p->tm_sec'. + external + "C struct struct tm access tm_sec use " + end + +note + copyright: "Copyright (c) 1984-2006, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 356 Storke Road, 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 C_DATE diff --git a/jj_temporal/classes/hms_constants.e b/jj_temporal/classes/hms_constants.e new file mode 100644 index 0000000..1f46265 --- /dev/null +++ b/jj_temporal/classes/hms_constants.e @@ -0,0 +1,34 @@ +note + description: "[ + Constants for use with HMS_TIME, HMS_DURATION, and HMS_INTERVAL. + ]" + date: "24 Aug 04" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + + +class + HMS_CONSTANTS + +feature -- Access + + One_second: HMS_DURATION + once + create Result.set (0, 0, 1) + end + + One_minute: HMS_DURATION + once + create Result.set (0, 1, 0) + end + + One_hour: HMS_DURATION + once + create Result.set (1, 0, 0) + end + +end -- class HMS_CONSTANTS diff --git a/jj_temporal/classes/hms_duration.e b/jj_temporal/classes/hms_duration.e new file mode 100644 index 0000000..bdf0658 --- /dev/null +++ b/jj_temporal/classes/hms_duration.e @@ -0,0 +1,281 @@ +note + description: "[ + A duration of time represented by hours, minutes, and seconds. + ]" + names: "duration, time_duration" + date: "1999/01/01"; updated: "14 Aug 04" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_DURATION + +inherit + + ABSTRACT_DURATION + +create + default_create, + set, + set_fine + +feature -- Access + + as_string: STRING_8 + -- The time represented as a string. + do + Result := hours.out + ":" + minutes.out + ":" + seconds.out + "." + milliseconds.out + end + + hours: INTEGER + -- The number of hours in this DURATION + + minutes: INTEGER + -- The number of minutes in this DURATION + + seconds: INTEGER + -- The number of seconds in this DURATION + + milliseconds: INTEGER + -- The number of milli-seconds in this DURATION + + as_hours: DOUBLE + -- Length of this duration in hours. + do + Result := hours + minutes / 60 + seconds / 3600 + milliseconds / 3600000 + end + + as_minutes: DOUBLE + -- Length of this duration in minutes. + do + Result := hours * 60 + minutes + seconds / 60 + milliseconds / 60000 + end + + as_seconds: DOUBLE + -- Length of this duration in seconds. + do + Result := hours * 3600 + minutes * 60 + seconds + milliseconds / 1000 + end + + as_milliseconds: DOUBLE + -- Length of this duration in milliseconds + do + Result := hours * 3600000 + minutes * 60000 + seconds * 1000 + milliseconds + end + + one: like Current + -- Neutral element for '*' and '/'. + do + create Result.set_fine (1, 1, 1, 1) + ensure then + result_hours_is_one: Result.hours = 1 + result_minutes_is_one: Result.minutes = 1 + result_seconds_is_one: Result.seconds = 1 + result_millisecons_is_one: Result.milliseconds = 1 + end + + zero: like Current + -- Neutral element for '+' and '-'. + do + create Result + ensure then + result_hours_is_zero: Result.hours = 0 + result_minutes_is_zero: Result.minutes = 0 + result_seconds_is_zero: Result.seconds = 0 + result_milliseconds_is_zero: Result.milliseconds = 0 + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + do + -- Used minutes because it seemed reasonable accuracy. + Result := as_minutes / other.as_minutes + end + +feature -- Element change + + set_zero + -- Make current have zero length. + do + set_fine (0, 0, 0, 0) + end + + set (a_hours, a_minutes, a_seconds: INTEGER) + -- Change the hours, minutes, and seconds to these values + -- and set milliseconds to zero. + do + set_fine (a_hours, a_minutes, a_seconds, 0) + ensure + hours_set: hours = a_hours + minutes_set: minutes = a_minutes + seconds_set: seconds = a_seconds + milliseconds_zero: milliseconds = 0 + end + + set_fine (a_hours, a_minutes, a_seconds, a_milliseconds: INTEGER) + -- Change `hours', `minutes', `seconds', and `milliseconds' + do + hours := a_hours + minutes := a_minutes + seconds := a_seconds + milliseconds := a_milliseconds + ensure + hours_set: hours = a_hours + minutes_set: minutes = a_minutes + seconds_set: seconds = a_seconds + milliseconds_set: milliseconds = a_milliseconds + end + + set_hours (a_hours: INTEGER) + -- Change hours + do + hours := a_hours + ensure + hours_set: hours = a_hours + end + + set_minutes (a_minutes: INTEGER) + -- change minutes + do + minutes := a_minutes + ensure + minutes_set: minutes = a_minutes + end + + set_seconds (a_seconds: INTEGER) + -- Change seconds + do + seconds := a_seconds + ensure + seconds_set: seconds = a_seconds + end + + negate + -- Reverses the sign for hours, minutes, and seconds. + do + hours := -hours + minutes := -minutes + seconds := -seconds + milliseconds := -milliseconds + ensure then + hours_negated: -hours = old hours + minutes_negated: -minutes = old minutes + seconds_negated: -seconds = old seconds + milliseconds_negated: milliseconds = -milliseconds + end + + normalize + -- Convert to standard format: "61 minutes" becomes "1 hour, 1 minute". + do +-- Fix me !!! for negatives... + seconds := seconds + milliseconds // 999 + milliseconds := milliseconds \\ 999 + minutes := minutes + seconds // 60 + seconds := seconds \\ 60 + hours := hours + minutes // 60 + minutes := minutes \\ 60 + end + + add (other: like Current) + -- Add 'other'. Does not 'normalize'. + do + hours := hours + other.hours + minutes := minutes + other.minutes + seconds := seconds + other.seconds + milliseconds := milliseconds + other.milliseconds + ensure then + hours_added: hours = old hours + other.hours + minutes_added: minutes = old minutes + other.minutes + seconds_added: seconds = old seconds + other.seconds + milliseconds_added: milliseconds = old milliseconds + other.milliseconds + end + + sub (other: like Current) + -- Subtract 'other'. Does not 'normalize'. + do + hours := hours - other.hours + minutes := minutes - other.minutes + seconds := seconds - other.seconds + milliseconds := milliseconds - other.milliseconds + ensure then + hours_subbed: hours = old hours - other.hours + minutes_subbed: minutes = old minutes - other.minutes + seconds_subbed: seconds = old seconds - other.seconds + milliseconds_subbed: milliseconds = old milliseconds - other.milliseconds + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + -- Result is normalized. + local + v: DOUBLE + fract: DOUBLE + do + -- Multiply `hours' + v := hours * r + hours := v.floor + fract := v - hours + -- Multiply `minutes' and add fractional of hour + v := minutes * r + 60 * fract + minutes := v.floor + fract := v - minutes + -- Mulitply `seconds' and add fractional minute + v := seconds * r + 60 * fract + seconds := v.floor + fract := v - seconds + -- Multiply `milliseconds' and add fractional second + v := milliseconds * r + 1000 * fract + milliseconds := v.rounded + -- Normalize + normalize + end + + divide (r: DOUBLE) + -- Divide by 'r'. + -- Result is normalized. + do + set_fine (0, 0, 0, (as_milliseconds / r).rounded) + normalize + end + + div (i: INTEGER) + -- Integer division. + -- Result is normalized. + do + set (0, 0, as_seconds.truncated_to_integer // i) + normalize + end + + mod (i: INTEGER) + -- Modulo. + -- Result is normalized. + do + set (0, 0, as_seconds.truncated_to_integer \\ i) + normalize + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Is 'Current' less than 'other'? + local + temp, temp_other: like Current + do + temp := twin + temp_other := other.twin + temp.normalize + temp_other.normalize + Result := (temp.hours < temp_other.hours) or + (temp.hours = temp_other.hours and temp.minutes < temp_other.minutes) or + (temp.hours = temp_other.hours and temp.minutes = temp_other.minutes and temp.seconds < temp_other.seconds) + end + +end + + + diff --git a/jj_temporal/classes/hms_interval.e b/jj_temporal/classes/hms_interval.e new file mode 100644 index 0000000..c7ca4e4 --- /dev/null +++ b/jj_temporal/classes/hms_interval.e @@ -0,0 +1,68 @@ +note + description: "[ + A span of time consisting of a start-time, finish-time + and duration described in terms of hours, minutes, and + seconds. Positive durations only. + ]" + names: "hms_interval, interval, time_span, time_interval, span" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_INTERVAL + +inherit + + ABSTRACT_INTERVAL + redefine + time_anchor, + duration_anchor + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Create an instance starting and ending at the default creation + -- value for the type of `start' time, having zero length duration. + do + -- Can't define `default_create' in ABSTRACT_INTERVAL because there + -- `start_imp' is deffered and cannot call create on a deferred type. + create start_imp + finish_imp := start_imp.twin + ensure then + same_start_and_finish: equal (start, finish) + zero_duration: duration.is_zero + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: HMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: HMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/classes/hms_time.e b/jj_temporal/classes/hms_time.e new file mode 100644 index 0000000..7cde6fe --- /dev/null +++ b/jj_temporal/classes/hms_time.e @@ -0,0 +1,551 @@ +note + description: "[ + An exact point of time as on a clock. An + Hour, Minute, Second time (ie. a time). + ]" + names: "time" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_TIME + +inherit + + ABSTRACT_TIME + rename + as_integer as as_seconds + redefine + default_create, + is_valid, + duration_anchor, + interval_anchor + end + +create + default_create, + set_now, + set_now_utc, + set_now_fine, + set_now_utc_fine, + set, + set_fine, + from_seconds, + from_string + +feature {NONE} -- Initialization + + default_create + -- Create an instance with time 00:00:00 (i.e. midnight). + do + end + +feature -- Access + + hour: INTEGER + -- Hour part of time. + + minute: INTEGER + -- Minute part of time. + + second: INTEGER + -- Second part of time. + + millisecond: INTEGER + -- Millisecond part of the time. + + overflow: INTEGER + -- Number of days after a normalize (49 hours gives 2 days overflow). + + as_string: STRING + -- The time represented as a string with no seperator characters, such + -- as ":", "-", or "/". The time 23:59:59.999 becomes "235959.999" + do + create Result.make (10) + if not (hour >= 10) then + Result.append ("0") + end + Result.append (hour.out) + if not (minute >= 10) then + Result.append ("0") + end + Result.append (minute.out) + if not (second >= 10) then + Result.append ("0") + end + Result.append (second.out) + Result.append (".") + if not (millisecond >= 100) then + Result.append ("0") + end + if not (millisecond >= 10) then + Result.append ("0") + end + Result.append (millisecond.out) + end + + as_seconds: INTEGER + -- The number of seconds from midnight to the current time. + -- `Millisecond' is rounded. + do + Result := hour * 60 * 60 + minute * 60 + second + (millisecond / 1000).rounded + end + +feature -- Element Change + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + local + h, m, s, mil: INTEGER + do + h := a_string.substring (1, 2).to_integer + m := a_string.substring (3, 4).to_integer + s := a_string.substring (5, 6).to_integer + mil := a_string.substring (8, 10).to_integer + set_fine (h, m, s, mil) + end + + from_seconds (a_seconds: INTEGER) + -- Initialize as `a_seconds' from midnight. + do + set (0, 0, 0) + add_seconds (a_seconds) + end + + set_now + -- Set current time according to timezone, setting `millisecond' to zero. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set_fine (C_date.hour_now, C_date.minute_now, C_date.second_now, 0) + end + + set_now_fine + -- Set current time according to timezone, including milli-seconds. + do + C_date.update + set_fine (C_date.hour_now, C_date.minute_now, C_date.second_now, C_date.millisecond_now) + end + + set_now_utc + -- Set the current object to today's date in utc format. + -- The `millisecond' is set to zero. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set (C_date.hour_now, C_date.minute_now, C_date.second_now) + end + + set_now_utc_fine + -- Set the current object to today's date in utc format, including `millisecond'. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set_fine (C_date.hour_now, C_date.minute_now, C_date.second_now, C_date.millisecond_now) + end + + set (h, m, s: INTEGER) + -- Change the hour, minute, and second. + -- Set `millisecond' to 0. + require + hour_valid: 0 <= h and h <= 23; + minute_valid: 0 <= m and m <= 59; + second_valid: 0 <= s and s <= 59 + do + set_fine (h, m, s, 0) + ensure + hour_assigned: hour = h + minute_assigned: minute = m + second_assigned: second = s + millisecond_assigned: millisecond = 0 + end + + set_fine (h, m, s, mil: INTEGER) + -- Change the hour, minute, and second + require + hour_valid: 0 <= h and h <= 23 + minute_valid: 0 <= m and m <= 59 + second_valid: 0 <= s and s <= 59 + millisecond_valid: 0 <= mil and mil <= 999999 + do + hour := h; + minute := m; + second := s; + millisecond := mil + ensure + hour_assigned: hour = h + minute_assigned: minute = m + second_assigned: second = s + millisecond_assigned: millisecond = mil + end + + set_hour (a_hour: INTEGER) + -- Change the `hour'. + require + hour_valid: 0 <= a_hour and a_hour <= 23; + do + hour := a_hour + ensure + hour_assigned: hour = a_hour + end + + set_minute (a_minute: INTEGER) + -- Change the `minute'. + require + minute_valid: 0 <= a_minute and a_minute <= 59; + do + minute := a_minute + ensure + minute_assigned: minute = a_minute + end + + set_second (a_second: INTEGER) + -- Change the second. + require + second_valid: 0 <= a_second and a_second <= 59 + do + second := a_second + ensure + second_assigned: second = a_second + end + + set_millisecond (a_millisecond: INTEGER) + -- Change the `millisecond' + require + valid_millisecond: 0 <= a_millisecond and a_millisecond <= 999 + do + millisecond := a_millisecond + ensure + millisecond_assigned: millisecond = a_millisecond + end + + from_integer (a_integer: INTEGER) + -- Change Current to the time represented by `a_integer'. + -- `A_compact_time' must represent a date that is not BC. + do +-- Fix me !!! + end + + clear_overflow + -- Remove the `overflow' condition by seting overflow to 0. + -- (Overflows occur when `add_duration' causes the time to be past 23:59:59.999) + do + overflow := 0 + end + + truncate_to_hours + -- Reset "to the hour" (set minutes and seconds to 0). + do + set_fine (hour, 0, 0, 0) + ensure + hour_unchanged: hour = old hour + minute_zero: minute = 0 + second_zero: second = 0 + millisecond_zero: millisecond = 0 + end + + truncate_to_minutes + -- Reset "to the minute" (i.e. set seconds to 0.) + do + set_fine (hour, minute, 0, 0) + ensure + hour_unchanged: hour = old hour + minute_unchanged: minute = old minute + second_zero: second = 0 + millisecond_zero: millisecond = 0 + end + + truncate_to_seconds + -- Set the `millisecond' to zero. + -- Use when `millisecond' portion is to be ignored. + do + set_millisecond (0) + ensure + hour_unchanged: hour = old hour + minute_unchanged: minute = old minute + second_unchaged: second = old second + millisecond_zero: millisecond = 0 + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does this time come before 'other'? + require else + other_time_not_void: other /= Void + do + Result := hour < other.hour or else + (hour = other.hour) and (minute < other.minute) or else + (hour = other.hour) and (minute = other.minute) and (second < other.second) or else + (hour = other.hour) and (minute = other.minute) and (second = other.second) and (millisecond < other.millisecond) + ensure then +-- definition: Result = (hour < other.hour) or else +-- (hour = other.hour) and (minute < other.minute) or else +-- (hour = other.hour) and (minute = other.minute) and (second < other.second) or else +-- (hour = other.hour) and (minute = other.minute) and (second = other.second) and (millisecond < other.millisecond) + end + + +feature -- Basic operations + + add_duration (a_duration: like Duration_anchor) + -- Add a length of time (in hours, minutes, and seconds) to the time. + do +-- hour := hour + a_duration.hours +-- minute := minute + a_duration.minutes +-- second := second + a_duration.seconds +-- millisecond := millisecond + a_duration.milliseconds + add_milliseconds (a_duration.milliseconds) + add_seconds (a_duration.seconds) + add_minutes (a_duration.minutes) + add_hours (a_duration.hours) + end + + add_hours (a_number: INTEGER) + -- Add `a_number' of hours to the current time + local + h: INTEGER + do + h := a_number \\ 24 + hour := hour + h + check + number_now_even: (a_number - h) \\ 24 = 0 + end + overflow := (a_number - h) // 24 + if hour < 0 then + check + positive_overflow: overflow >= 1 + end + hour := hour + 24 + overflow := overflow - 1 + end + if hour >= 24 then + hour := hour - 24 + overflow := overflow + 1 + end + end + + add_minutes (a_number: INTEGER) + -- Add `a_number' of minutes to the current time. + local + m: INTEGER + do + minute := minute + a_number + m := minute + minute := minute \\ 60 + if minute < 0 then + minute := minute + 60 + add_hours (-1) + end + add_hours (m // 60) + end + + add_seconds (a_number: INTEGER) + -- Add `a_number' of seconds to the current time. + local + s: INTEGER + do + second := second + a_number + s := second + second := second \\ 60 + if second < 0 then + second := second + 60 + add_minutes (-1) + end + add_minutes (s // 60) + end + + add_milliseconds (a_number: INTEGER) + -- Add `a_number' of milliseconds to the current time. + local + ms: INTEGER + do + millisecond := millisecond + a_number + ms := millisecond + millisecond := millisecond \\ 1000 + if millisecond < 0 then + millisecond := millisecond + 1000 + add_seconds (-1) + end + add_seconds (ms // 1000) + end + +feature -- Status report + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + -- Caveat: the `milliseconds' will be lost due to rounding in `as_seconds'. + do + Result := True + end + +feature -- Querry + + time_between (other: like Current): like Duration_anchor + -- A length of time in hours, minutes, and seconds + -- between this time and other. + local + larger, smaller: like Current + h, m, s, ms: INTEGER + do + larger := max (other) + smaller := min (other) + ms := larger.millisecond - smaller.millisecond + h := larger.hour - smaller.hour + m := larger.minute - smaller.minute + s := larger.second - smaller.second + if ms < 0 then + ms := ms + 999 + s := s - 1 + end + if s < 0 then + s := s + 60 + m := m - 1 + end + if m < 0 then + m := m + 60 + h := h - 1 + end + create Result.set_fine (h, m, s, ms) + if Current < other then + Result.negate + end + end + + seconds_between (a_other: like Current): INTEGER + -- The number of seconds between Current and `other' + require + other_exists: a_other /= Void + local + larger, smaller: like Current + h, m, s, ms: INTEGER + do + larger := max (a_other) + smaller := min (a_other) + ms := larger.millisecond - smaller.millisecond + h := larger.hour - smaller.hour + m := larger.minute - smaller.minute + s := larger.second - smaller.second + if ms < 0 then + ms := ms + 999 + s := s - 1 + end + if s < 0 then + s := s + 60 + m := m - 1 + end + if m < 0 then + m := m + 60 + h := h - 1 + end + Result := h * 60 * 60 + m * 60 + s + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + local + hs, ms, ss, mils: STRING + h, m, s, mil: INTEGER + do + if a_string /= Void and then a_string.count = 10 and then equal (a_string.substring (7, 7), ".") then + hs := a_string.substring (1, 2) + ms := a_string.substring (3, 4) + ss := a_string.substring (5, 6) + mils := a_string.substring (8, 10) + if hs.is_integer and then ms.is_integer and then ss.is_integer and then mils.is_integer then + h := hs.to_integer + m := ms.to_integer + s := ms.to_integer + mil := mils.to_integer + if (h >= 0 and h <= 23) and then + (m >= 0 and m <= 59) and then + (s >= 0 and s <= 59) and then + (mil >= 0 and mil <= 999) then + Result := True + end + end + end + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in range to be converted to a time? + do + Result := a_integer >= 0 + end + +feature {NONE} -- Implementation + +-- normalize is +-- -- convert to a normal time (1 minute, 60 seconds becomes 2 minutes 0 seconds) +-- do +-- second := second + millisecond // 999 +-- millisecond := millisecond \\ 999 +-- if millisecond < 0 then +-- millisecond := millisecond + 999 +-- second := second - 1 +-- end +-- minute := minute + second // 60 +-- second := second \\ 60 +-- if second < 0 then +-- second := second + 60 +-- minute := minute - 1 +-- end +-- hour := hour + minute // 60 +-- minute := minute \\ 60 +-- if minute < 0 then +-- minute := minute + 60 +-- hour := hour - 1 +-- end +-- overflow := hour // 24 +-- hour := hour \\ 24 +-- if hour < 0 then +-- hour := hour + 24 +-- overflow := overflow - 1 +-- end +-- end + + is_valid: BOOLEAN + -- Is time in correct format? + do + Result := (0 <= millisecond and millisecond <= 999) and + (0 <= second and second <= 59) and + (0 <= minute and minute <= 59) and + (0 <= hour and hour <= 23) + ensure then + valid_result: Result implies + (0 <= millisecond and millisecond <= 999) and + (0 <= second and second <= 59) and + (0 <= minute and minute <= 59) and + (0 <= hour and hour <= 23) + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: HMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: HMS_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/classes/hms_timer.e b/jj_temporal/classes/hms_timer.e new file mode 100644 index 0000000..8312b26 --- /dev/null +++ b/jj_temporal/classes/hms_timer.e @@ -0,0 +1,74 @@ +note + description: "[ + Timer for hours, minutes, seconds, and miliseconds. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_TIMER + +inherit + + HMS_INTERVAL + undefine + duration, + out + redefine + default_create, + time_anchor, + duration_anchor + end + + TIMER + undefine + time_anchor, + duration_anchor + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Set up the timer + do + Precursor {HMS_INTERVAL} + Precursor {TIMER} + create cumulative + end + + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: HMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: HMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + +end diff --git a/jj_temporal/classes/time_stampable.e b/jj_temporal/classes/time_stampable.e new file mode 100644 index 0000000..859df28 --- /dev/null +++ b/jj_temporal/classes/time_stampable.e @@ -0,0 +1,60 @@ +note + description: "[ + Objects which record their creation time. + ]" + date: "1 Sep 04" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + TIME_STAMPABLE + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Initialize `Current'. + do + create timestamp.set_now_utc_fine + end + +feature -- Access + + id: STRING + -- Unique (hopefully) object id based on the creation time of the object. + -- Concatination of Current's `generating_type' and `time_stamp'. + do + Result := generating_type.name.to_string_8 + " " + timestamp.as_string + end + + timestamp: YMDHMS_TIME + -- Time this object was created + +--feature -- Comparison + +-- infix "<" (a_other: like Current): BOOLEAN is +-- -- Is Current less than `a_other'? +-- do +-- Result := id < a_other.id +---- Result := timestamp < a_other.timestamp +-- end + +invariant + + time_stamp_exists: timestamp /= Void + +end diff --git a/jj_temporal/classes/timer.e b/jj_temporal/classes/timer.e new file mode 100644 index 0000000..04f61b9 --- /dev/null +++ b/jj_temporal/classes/timer.e @@ -0,0 +1,122 @@ +note + description: "[ + Stop-watch type object. + Create the object and call `reset' to use. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + TIMER + +inherit + + ABSTRACT_INTERVAL + redefine + duration + end + +feature {NONE} -- Initialization + + default_create + -- Initialize Current + do + create lap_times.make (10) + end + +feature -- Access + + duration: like duration_anchor + -- The time between the `start' and the `finish'; + -- or the time between the `start' and the current time if + -- the timer is running. + local + t: like time_anchor + do + if is_running then + t := finish + t.set_now_utc_fine + Result := t.time_between (start) + else + Result := Precursor + end + end + + cumulative: like duration_anchor + -- Cumulative total of all the times elapsed on the timer. + -- Recalculated at every `stop'. + + i_th_lap (a_index: INTEGER): like duration_anchor + -- The `a_index'th duration. + require + is_valid_lap_index: is_valid_lap_index (a_index) + do + Result := lap_times.i_th (a_index) + end + +feature -- Status report + + is_running: BOOLEAN + -- Is the timer running? + -- (Use `start' to begin timing and `stop' to end.) + +feature -- Basic operations + + reset + -- Reset `elapsed' to zero. + do + start_imp.set_now_utc_fine + finish_imp.copy (start) + cumulative.set_zero + lap_times.wipe_out + end + + run + -- Start the timer + require + not_running: not is_running + do + is_running := True + start_imp.set_now_utc_fine + ensure + is_running: is_running + end + + stop + -- Stop the timer + require + is_running: is_running + do + is_running := False + finish_imp.set_now_utc_fine + cumulative := cumulative + duration +-- start_imp.copy (finish) +-- mark_lap + ensure + is_stopped: not is_running + end + + mark_lap + -- Record the current `lap' time in `lap_times' but keep the timer running. + do + lap_times.extend (duration) + end + +feature -- Querry + + is_valid_lap_index (a_index: INTEGER): BOOLEAN + -- Is `a_index' a valid value into the list of `lap_times'? + do + Result := lap_times.valid_index (a_index) + end + +feature {NONE} -- Implementation + + lap_times: ARRAYED_LIST [like duration_anchor] + -- List of durations for each time `mark_lap' was called. + +end diff --git a/jj_temporal/classes/ymd_constants.e b/jj_temporal/classes/ymd_constants.e new file mode 100644 index 0000000..1acf83d --- /dev/null +++ b/jj_temporal/classes/ymd_constants.e @@ -0,0 +1,48 @@ +note + description: "[ + Constants for use with YMD_TIME, YMD_DURATION, and YMD_INTERVAL. + ]" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_CONSTANTS + +feature -- Access + + One_day: YMD_DURATION + once + create Result + Result.set (0, 0, 1) + end + + One_week: YMD_DURATION + once + create Result + Result.set (0, 0, 7) + end + + One_month: YMD_DURATION + once + create Result + Result.set (0, 1, 0) + end + + One_quarter: YMD_DURATION + once + create Result + Result.set (0, 3, 0) + end + + One_year: YMD_DURATION + once + create Result + Result.set (1, 0, 0) + end + +end -- class YMD_CONSTANTS diff --git a/jj_temporal/classes/ymd_duration.e b/jj_temporal/classes/ymd_duration.e new file mode 100644 index 0000000..3ddc736 --- /dev/null +++ b/jj_temporal/classes/ymd_duration.e @@ -0,0 +1,325 @@ +note + description: "[ + Duration of time described in years, months, and days. + ]" + names: "ymd_duration" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_DURATION + +inherit + + ABSTRACT_DURATION + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Create an instance with zero length. + do + days_per_month := default_days_per_month + set (0, 0, 0) + end + +feature -- Access + + as_string: STRING_8 + -- The time represented as a string. + do + Result := years.out + ":" + months.out + ":" + days.out + end + + years: INTEGER + -- Number of years part. + -- Does not consider the months or days. + + months: INTEGER + -- Number of months part. + -- Does not consider the years or days. + + days: INTEGER + -- Number of days part. + -- Does not consider the months or years. + + default_days_per_month: DOUBLE = 30.4375 + -- Default value for 'days_per_month'. + -- 365.25 days per year divided by 12 months per year. + + days_per_month: DOUBLE + -- Number of days in a month. (28?, 29?, 30?, 31?) + -- Value assumed by class to do calculations involving conversion + -- from days to months to years. + -- Default = 30.4375 days / month. + + days_per_year: DOUBLE + -- Number of days in the year. Calculated based on 'days_per_month'. + -- Value assumed by class to do calculations involving conversion + -- from days to months to years. + -- Default = 365.25 days / year. + do + Result := days_per_month * 12 + end + + as_years: DOUBLE + -- Length of duration in years. + do + Result := years + months / 12 + days / days_per_year + end + + as_months: DOUBLE + -- Length of duration in months. + do + Result := years * 12 + months + days / days_per_month + end + + as_days: DOUBLE + -- Length of duration in days. + do + Result := years * days_per_year + months * days_per_month + days + end + + one: like Current + -- Neutral element for "*" and "/" + do + create Result + Result.set (1,1,1) + ensure then + result_years_is_one: Result.years = 1 + result_months_is_one: Result.months = 1 + result_days_is_one: Result.days = 1 + end + + zero: like Current + -- Neutral element for "+" and "-" + do + create Result + ensure then + result_years_is_zero: Result.years = 0 + result_months_is_zero: Result.months = 0 + result_days_is_zero: Result.days = 0 + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + -- For example: is current duration at least twice as long as other? + do +-- Result := as_months / other.as_months -- Used months because it seemed reasonable accuracy. + Result := as_days / other.as_days -- Must use days because of accuracy problems with month length. + end + + normalized: like Current + -- A copy of Current in a normalized form. + do + Result := twin + Result.normalize + end + +feature -- Element change + + set_zero + -- Make Current have zero length. + do + set (0, 0, 0) + end + + set (ys, ms, ds: INTEGER) + -- Change the length of years, months, and days. + do + years := ys + months := ms + days := ds + ensure + years_set: years = ys + months_set: months = ms + days_set: days = ds + end + + set_years (ys: INTEGER) + -- Change years + do + years := ys + ensure + years_set: years = ys + end + + set_months (ms: INTEGER) + -- Change months + do + months := ms; + ensure + months_set: months = ms + end + + set_days (ds: INTEGER) + -- Change days + do + days := ds + ensure + days_set: days = ds + end + + set_days_per_month (i: DOUBLE) + -- Change 'days_per_month' (value used in calculations + -- involving month lenghts). + require + in_range: i >= 28 and i <= 31 + do + days_per_month := i + ensure + days_per_month_set: days_per_month = i + end + +feature -- Basic operations + + negate + -- Reverse the sign on years, months, and days. + do + years := -years; + months := -months; + days := -days + ensure then + years_negated: -years = old years + months_negated: -months = old months + days_negated: -days = old days + end + + normalize + -- Convert to standard format: "13 months" becomes "1 year, 1 month". + -- Month and year length is based on 'days_per_month'. + -- This feature is hard to define. For example, is 28 days equal to + -- one month? What about 30 days? + -- This needs to be fixed. + require + days_per_month > 0 + local + m, d: DOUBLE + dpm: DOUBLE + do + -- The check on `days_per_month' was necessary because `<' which calls + -- this feature must be getting called before the object is fully + -- initialized, so at that point `days_per_month' is zero; this check + -- prevents that "floating point exception". + if days_per_month = 0 then + dpm := Default_days_per_month + else + dpm := days_per_month + end + d := days + m := d / dpm + months := months + m.truncated_to_integer + m := m - m.truncated_to_integer + d := m * dpm + days := d.truncated_to_integer +-- if (d - days) > 0.5 then +-- days := days + 1 +-- if days > dpm then +-- months := months + 1 +-- end +-- end + years := years + months // 12 + months := months \\ 12 + end + + add (other: like Current) + -- Add other to current. + do + years := years + other.years; + months := months + other.months; + days := days + other.days + ensure then + years_added: years = old years + other.years + months_added: months = old months + other.months + days_add: days = old days + other.days + end + + sub (other: like Current) + -- Subtract other from current. + do + years := years - other.years; + months := months - other.months; + days := days - other.days + ensure then + years_subbed: years = old years - other.years + months_subbed: months = old months - other.months + days_subbed: days = old days - other.days + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + -- Result is normalized. + local + v: DOUBLE + fract: DOUBLE + do + v := years * r + years := v.floor + fract := v - years + + v := months * r + 12 * fract + months := v.floor + fract := v - months + + v := days * r + days_per_month * fract + days := v.rounded + normalize + end + + divide (r: DOUBLE) + -- Divide by 'r'. + -- Result is normalized. + do + set (0, 0, (as_days / r).rounded) + normalize + end + + + div (i: INTEGER) + -- Integer division. + -- Result is normalized. + do + set (0, 0, (as_days / i).truncated_to_integer) + normalize + end + + mod (i: INTEGER) + -- Modulo of duration with 'i'. + -- Result is normalized. + do + set (0, 0, as_days.truncated_to_integer \\ i) + normalize + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Is current shorter than other? + local + temp, temp_other: like Current + do + temp := twin + temp_other := other.twin + temp.normalize + temp_other.normalize + Result := (temp.years < temp_other.years) or else + (temp.years = temp_other.years and temp.months < temp_other.months) or else + (temp.years = temp_other.years and temp.months = temp_other.months and temp.days < temp_other.days) + end + +invariant + + days_per_month_in_range: days_per_month >= 28 and days_per_month <= 31 + + +end -- class YMD_DURATION + diff --git a/jj_temporal/classes/ymd_interval.e b/jj_temporal/classes/ymd_interval.e new file mode 100644 index 0000000..3667805 --- /dev/null +++ b/jj_temporal/classes/ymd_interval.e @@ -0,0 +1,67 @@ +note + description: "[ + A span of time consisting of a start-time, finish-time and duration + described in terms of years, months, and days. Positive durations only. + ]" + names: "ymd_interval, interval, time_span, time_interval, span" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_INTERVAL + +inherit + + ABSTRACT_INTERVAL + redefine + time_anchor, + duration_anchor + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Create an instance starting and ending at the default creation + -- value for the type of `start' time, having zero length duration. + do + -- Can't define `default_create' in ABSTRACT_INTERVAL because there + -- `start_imp' is deffered and cannot call create on a deferred type. + create start_imp + finish_imp := start_imp.twin + ensure then + same_start_and_finish: equal (start, finish) + zero_duration: duration.is_zero + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMD_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMD_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/classes/ymd_time.e b/jj_temporal/classes/ymd_time.e new file mode 100644 index 0000000..fa1c479 --- /dev/null +++ b/jj_temporal/classes/ymd_time.e @@ -0,0 +1,671 @@ +note + description: "[ + An exact point of time as on a gregorian callendar. + Has a `Year', `Month', and `Day' (i.e. a date). + ]" + names: "date, time" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME + +inherit + + ABSTRACT_TIME + rename + as_integer as as_days, + from_integer as from_days + redefine + default_create, + is_valid, + duration_anchor, + interval_anchor + end + +create + default_create, + set_now, + set_now_utc, + set, + from_days, + from_string + +feature {NONE} -- Initialization + + default_create + -- Create an instance based on todays date. + do + set_now + end + +feature -- Access + + year: INTEGER + -- Year part of the date. + + month: INTEGER + -- Month part of the date. + + day: INTEGER + -- Day part of the date. + do + Result := internal_day + if Result > last_day_of_month then + Result := last_day_of_month + end + end + + week_number: INTEGER + -- Week of the year containing this date. + local + d: YMD_TIME + first_d: INTEGER -- Jan 1st is on what day? + do + create d + d.set (year, 1, 1) + first_d := d.weekday + Result := (((julian + first_d - 1 - 1) // 7) + 1) + ensure + result_large_enough: Result >= 1 + result_small_enough: Result <= 54 -- 53 ? 54 if leapyear falls just right. + end + + last_day_of_month: INTEGER + -- Date of last day for current month + do + inspect + month + when 2 then + if is_leapyear then + Result := 29 + else + Result := 28 + end + when 4, 6, 9, 11 then + Result := 30 + else + Result := 31 + end + ensure + day_in_range: Result >= 28 and Result <= 31 + good_not_leap: Result = 28 implies (month = 2 and not is_leapyear) + good_in_leap: Result = 29 implies (month = 2 and is_leapyear) + good_30s: Result = 30 implies (month = 4 or month = 6 or month = 9 or month = 11) + good_31s: Result = 31 implies (month=1 or month=3 or month=5 or month=7 or month=8 or month=10 or month=12) + end + + days_remaining_this_month: INTEGER + -- Number of days from current until end of month. + -- Used in some calculations. + do + Result := last_day_of_month - day + ensure + valid_result: Result >= 0 and Result < last_day_of_month + end + + julian: INTEGER + -- Day of the year between 1 and 366 + local + n,i : INTEGER + do + from + i := 1 + until + i >= month + loop + inspect i + when 2 then + if is_leapyear then + n := n + 29 + else + n := n + 28 + end + when 4,6,9,11 then + n := n + 30 + else + n := n + 31 + end + i := i + 1 + end + result := n + day + ensure + valid_leapyear_result: is_leapyear implies (1 <= Result and Result <= 366) + valid_result: not is_leapyear implies (1 <= Result and Result <= 365) + end + + + weekday: INTEGER + -- 1 for Sunday, 2 for Monday, etc + -- Only works as far back as ~2 Mar 0001. ??? + local + x : INTEGER + do + x := internal\\7 + 1 + 1 + if x > 7 then -- it can only be 8 + x := 1 + end + result := x + ensure + valid_weekday: 1 <= Result and Result <= 7 + end + + as_string: STRING + -- The date represented as a string with no spaces. + -- 18 Jan 2005 would be "20050118". + do + create Result.make (10) + if is_bc then + Result.append ("BC") + end + if not (year.abs >= 1000) then + Result.append ("0") + end + if not (year.abs >= 100) then + Result.append ("0") + end + if not (year.abs >= 10) then + Result.append ("0") + end + Result.append (year.abs.out) + if not (month >= 10) then + Result.append ("0") + end + Result.append (month.out) + if not (day >= 10) then + Result.append ("0") + end + Result.append (day.out) + end + + as_days: INTEGER + -- The number of days from midnight (00:00:00) + -- on 1 Jan 1970 to the beginning Current's `day'. + local + t: YMD_TIME + do + create t + t.set (1970, 1, 1) + Result := days_between (t) + end + +feature -- Element Change + + from_days (a_days: INTEGER) + -- Change Current to the time represented by `a_days'. + -- `A_days' is assumed to be the number of days since 1 Jan 1970. + -- `A_days' must represent a date that is not BC + do + set (1970, 1, 1) + add_days (a_days) + end + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + local + d, m, y: INTEGER + do + y := a_string.substring (1, 4).to_integer + m := a_string.substring (5, 6).to_integer + d := a_string.substring (7, 8).to_integer + set (y, m, d) + end + + set_now + -- Set the current object to today's date. + -- This was copied from ISE's DATE class with the one minor change. + do + C_date.update + set (C_date.year_now, C_date.month_now, C_date.day_now) + end + + set_now_utc + -- Set the current object to today's date in utc format. + -- This was copied from ISE's DATE class with the one minor change. + do + C_date.update + set (C_date.year_now, C_date.month_now, C_date.day_now) + end + + set_now_utc_fine + -- Set the current object to today's date in utc format. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set (C_date.year_now, C_date.month_now, C_date.day_now) + end + + set (a_year, a_month, a_day: INTEGER) + -- Give date new year, month, and day. + -- If day > num days in month then day will return last day in the month. + require + realistic_year: a_year /= 0 + realistic_month: a_month >= 1 and a_month <= 12 + realistic_day: a_day >= 1 and a_day <= 31 + do + year := a_year + month := a_month + internal_day := a_day + ensure + year_assigned: year = a_year + month_assigned: month = a_month + day_assigned: day = a_day + end + + set_year (a_year: INTEGER) + -- Change the year. + require + realistic_year: a_year /= 0 + do + year := a_year + ensure + year_assigned: year = a_year + end + + set_month (a_month: INTEGER) + -- Change the month. + require + realistic_month: a_month >= 1 and a_month <= 12 + do + month := a_month + ensure + month_assigned: month = a_month + end + + set_day (a_day: INTEGER) + -- Change the day. + -- If a_day > number of days in the month then + -- 'day' will be the last day of month. + require + realistic_day: a_day >= 1 and a_day <= 31 + do + internal_day := a_day + ensure + day_assigned: day = a_day + end + + truncate_to_years + -- Set the day to first day of month 1. + -- Use when all but the `year' is to be ignored. + do + set_day (1) + set_month (1) + ensure + year_unchanged: year = old year + month_one: month = 1 + day_one: day = 1 + end + + truncate_to_months + -- Set day to first day of current month. + -- Use when the `day' portion of date is to be ignored. + do + set_day (1) + ensure + year_unchanged: year = old year + month_unchanged: month = old month + day_one: day = 1 + end + +feature -- Status report + + is_leapyear: BOOLEAN + -- Is this a leapyear? + do + if is_bc then + Result := (year + 1) \\ 4 = 0 and not ((year + 1) \\ 400 = 0) + else + Result := year \\ 4 = 0 and (not (year \\ 100 = 0) or else year \\ 400 = 0) + end + end + + is_bc: BOOLEAN + -- Does the date represent a date B.C. (ie year < 1) + do + Result := year <= -1 + ensure + definition: Result implies year <= -1 + end + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + do + Result := not is_bc and then + (Current >= Minimum_representable_date and Current <= Maximum_representable_date) + end + +feature -- Querry + + days_between (other: like Current): INTEGER + -- Days between this date and 'other'. + -- Only works back to ~2 Mar 0001. + require + other_exists : other /= Void + do + Result := (other.internal - internal).abs + ensure + definition: Result = (other.internal - internal).abs + end + + time_between (other: like Current): like Duration_anchor + -- The difference between two dates as a duration + local + larger, smaller: like Current + y, m, d: INTEGER + do + larger := max (other) + smaller := min (other) + y := larger.year - smaller.year + m := larger.month - smaller.month + d := larger.day - smaller.day + if d < 0 then + d := d + smaller.last_day_of_month + m := m - 1 + end + if m < 0 then + m := m + 12 + y := y - 1 + end + create Result + Result.set (y, m, d) + if Current < other then + Result.negate + end + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in range to be converted to a time? + -- Dependent on the `internal' representation of dates. + do + -- These values were found by trial and error. This will give a + -- date from 1 Jan 0001 to 18 Oct 1,469,902, which, I believe, is + -- far enough into the future. + Result := a_integer >= 1721426 and a_integer <= 538592032 + ensure then + definition: Result implies (a_integer >= 1721426) and then + (a_integer <= 538592032) -- dependent on `internal' + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + local + bcs: detachable STRING + ys, ms, ds: STRING + y, m, d: INTEGER + pad: INTEGER -- add 2 if is "BC" + do + if a_string /= Void and then (a_string.count = 8 or a_string.count = 10) then + if a_string.count = 10 then + pad := 2 + bcs := a_string.substring (1, 2) + end + ys := a_string.substring (1 + pad, 4 + pad) + ms := a_string.substring (5 + pad, 6 + pad) + ds := a_string.substring (7 + pad, 8 + pad) + if ys.is_integer and then ms.is_integer and then ds.is_integer then + y := ys.to_integer + m := ms.to_integer + d := ds.to_integer + if (y /= 0) and then (m >= 0 and m < 12)and then (d >= 0 and d <= 31) then + Result := True + if bcs /= Void and then not equal (bcs, "BC") then + Result := False + end + end + end + end + end + +feature -- Basic operations + + add_years (a_num: INTEGER) + -- Add 'a_num' number of years to the date. Works for negative numbers also. + local + y: INTEGER + do + y := year + year := year + a_num + if year = 0 then -- Must preserve invarient: year can not be 0. + if y < 0 then -- year was less than 0 and increased to 0. + year := 1 + else -- year was greater than 0 and decreased to 0. + year := -1 + end + end + ensure + valid_date: is_valid + end + + add_months (a_num: INTEGER) + -- Add 'a_num' number of months to the date. Works for negative numbers also. + local + m: INTEGER -- store month prior making month valid to call 'add_years'. + do + month := month + a_num + m := month + month := month \\ 12 -- preserve invarient + if month < 1 then + month := month + 12 -- preserve invarient + add_years (-1) + end + add_years (m // 12) -- add a year for every multiple of 12. + ensure + valid_date: is_valid + end + + add_days (a_num: INTEGER) + -- Add 'a_num' number of days to the date. Works for negative numbers also. + local + i: INTEGER + do + if a_num > 0 then + from i := a_num + until i <= days_remaining_this_month + loop + i := i - (days_remaining_this_month + 1) + set_day (1) + add_months (1) + end + set_day (day + i) + elseif a_num < 0 then + from + i := a_num.abs + until + i < day + loop + i := (day - i).abs + add_months (-1) + set_day (last_day_of_month) + end + set_day (day - i) + else + -- do nothing if a_num = 0 + end + ensure + valid_date: is_valid + end + + add_duration (a_duration: like Duration_anchor) + -- Add a length of time (in years, months, and days) to the date. + do + add_days (a_duration.days) + add_months (a_duration.months) + add_years (a_duration.years) + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does this date come before 'other'? + require else + other_not_void: other /= Void + do + Result := year < other.year or else + (year = other.year) and (month < other.month) or else + (year = other.year) and (month = other.month) and (day < other.day) + ensure then +-- definition: year < other.year or else +-- (year = other.year) and (month < other.month) or else +-- (year = other.year) and (month = other.month) and (day < other.day) + end + +feature {YMD_TIME} -- Implementation + + frozen internal: INTEGER + -- Internal representation of YMD_TIME + -- Used internally by some features. + -- Does not work for BC dates; only works back to 1 January 0001, + -- at which time the result is 1,721,426. + -- Will work up to a date of 18 Oct 1,469,902 (found by trial). + require + not_bc: not is_bc + local + c, ya : INTEGER; + d,m,y : INTEGER; + do + d := day; + m := month; + y := year; + if m > 2 then + m := m - 3; + else + m := m + 9; + y := y - 1; + end + c := y // 100; + ya := y - 100 * c; + result := (146097 * c) // 4 + (1461 * ya) // 4 + (153 * m + 2) // 5 + d + 1721119; + ensure + result_large_enough: Result >= 1721426 + result_small_enough: Result <= 538592032 + end + + frozen from_internal (num: INTEGER) + -- Create a YMD_TIME from an internal representation. + local + y,m,d,j : INTEGER + do + j := num; + j := j - 1721119 + y := (4 * j - 1) // 146097; j := 4 * j - 1 - 146097 * y; + d := j // 4; + j := (4 * d + 3) // 1461; d := 4 * d + 3 - 1461 * j; + d := (d + 4) // 4; + m := (5 * d - 3) // 153; d := 5 * d - 3 - 153 * m; + d := (d + 5) // 5; + y := 100 * y + j; + if m < 10 then + m := m + 3; + else + m := m - 9; + y := y + 1; + end; + internal_day := d; + month := m; + year := y; + end + +feature {NONE} -- Implementation + + internal_day: INTEGER + -- Used to save last day of month if day is greater than 28, 30, or 31. + -- Actual day is calculated from this value. + + is_valid: BOOLEAN + -- Is the date logical? + do + Result := is_valid_year and is_valid_month and is_valid_day + end + + is_valid_year: BOOLEAN + -- Is the year logical? + -- Only invalid year is year "0". + do + Result := year /= 0 + ensure + definition: year /= 0 + end + + is_valid_month: BOOLEAN + -- Is the month logical? + do + Result := 1 <= month and month <= 12 + ensure + definition: 1 <= month and month <= 12 + end + + is_valid_day: BOOLEAN + -- Is the day logical based on month and year? + do + Result := day >= 1 and then + ( (day <= 28) or else + ((month=4 or month=6 or month=9 or month=11) and then day <= 30) or else + ((month=1 or month=3 or month=5 or month=7 or month=8 or month=10 or month=12) and then day <= 31) or else + (month=2 and is_leapyear and day <= 29) ) + end + +feature {NONE} -- Implementation + + Minimum_representable_date: like Current + -- The earliest date that can be represented as an integer. + -- This value is dependent on the implementation of `internal' and + -- was found by trial and error to be 1 Jan 0001. + do + create Result + Result.set_year (1) + Result.set_month (1) + Result.set_day (1) + end + + Maximum_representable_date: like Current + -- The latest date that can be represented as an integer. + -- This value is dependent on the implementation of `internal' and + -- was found by trial and error to be 18 Oct 1,469,902. + do + create Result + Result.set_year (1_469_902) + Result.set_month (10) + Result.set_day (18) + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: YMD_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require else + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: YMD_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require else + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +invariant + + is_valid: is_valid + +end -- class YMD_TIME + + diff --git a/jj_temporal/classes/ymd_timer.e b/jj_temporal/classes/ymd_timer.e new file mode 100644 index 0000000..45b49aa --- /dev/null +++ b/jj_temporal/classes/ymd_timer.e @@ -0,0 +1,73 @@ +note + description: "[ + Timer for hours, minutes, seconds, and miliseconds. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: $" + revision: "$Revision: $" + +class + YMD_TIMER + +inherit + + YMD_INTERVAL + undefine + duration + redefine + default_create, + time_anchor, + duration_anchor + end + + TIMER + undefine + time_anchor, + duration_anchor + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Set up the timer + do + Precursor {YMD_INTERVAL} + Precursor {TIMER} + create cumulative + end + + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMD_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMD_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + +end diff --git a/jj_temporal/classes/ymdhms_duration.e b/jj_temporal/classes/ymdhms_duration.e new file mode 100644 index 0000000..1805d6e --- /dev/null +++ b/jj_temporal/classes/ymdhms_duration.e @@ -0,0 +1,268 @@ +note + description: "[ + Duration of time described in years, months, days, + hours, minutes, and seconds. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_DURATION + +inherit + + YMD_DURATION + rename + set as ymd_set, + as_string as as_ymd_string + redefine + default_create, + zero, one, + set_zero, + as_years, as_months, as_days, + add, sub, multiply, divide, div, mod, negate, percent_of, + is_less, + normalize + end + + HMS_DURATION + rename + set as hms_set, + as_string as as_hms_string + redefine + default_create, + zero, one, + set_zero, + as_hours, as_minutes, as_seconds, + add, sub, multiply, divide, div, mod, negate, percent_of, + is_less, + normalize + select + as_hms_string + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + Precursor {YMD_DURATION} + Precursor {HMS_DURATION} + end + +feature -- Access + + as_string: STRING_8 + -- The time represented as a string. + do + Result := as_ymd_string + ":" + as_hms_string + end + + zero: like Current + -- Neutral element for "+" and "-" + do + create Result + end + + one: like Current + -- Neutral element for "*" and "/" + do + create Result + Result.set (1,1,1,1,1,1) + end + + as_years: DOUBLE + -- Length of duration in years. + do + Result := years + months / 12 + days / days_per_year + + hours / (24 * days_per_year) + minutes / (60 * 24 * days_per_year) + + seconds / (60 * 60 * 24 * days_per_year) + end + + as_months: DOUBLE + -- Length of duration in months. + do + Result := years * 12 + months + days / days_per_month + + hours / hours_per_month + minutes / (60 * hours_per_month) + + seconds / (60 * 60 * hours_per_month) + end + + as_days: DOUBLE + -- Length of duration in days. + do + Result := years * days_per_year + months * days_per_month + days + + hours / 24 + minutes / (24 * 60) + seconds / (24 * 60 * 60) + end + + as_hours: DOUBLE + -- Length of this duration in hours. + do + Result := (years * days_per_year + months * days_per_month + days) -- number of days + * 24 + hours + minutes / 60 + seconds / 3600 + end + + as_minutes: DOUBLE + -- Length of this duration in minutes. + do + Result := ((years * days_per_year + months * days_per_month + days) -- number of days + * 24 + hours) -- number of hours + * 60 + minutes + seconds / 60 + end + + as_seconds: DOUBLE + -- Length of this duration in seconds. + do + Result := (((years * days_per_year + months * days_per_month + days) -- number of days + * 24 + hours) -- number of hours + * 60 + minutes) -- number of minutes + * 60 + seconds + end + +feature -- Element change + + set (a_year, a_month, a_day, a_hour, a_minute, a_second: INTEGER) + -- Change years, months, days, hours, minutes, seconds. + do + ymd_set (a_year, a_month, a_day) + hms_set (a_hour, a_minute, a_second) + ensure + years_set: years = a_year + months_set: months = a_month + days_set: days = a_day + hours_set: hours = a_hour + minutes_set: minutes = a_minute + seconds_set: seconds = a_second + end + + set_zero + -- Make the duration be zero length. + do + ymd_set (0, 0, 0) + set_fine (0, 0, 0, 0) + end + + + negate + -- Reverse the sign for years, ..., seconds. + do + Precursor {YMD_DURATION} + Precursor {HMS_DURATION} + end + + normalize + -- Convert to standard format: "13 months" becomes "1 year, 1 month". + -- Month and year length is based on 'days_per_month'. + do + Precursor {HMS_DURATION} + set_days (days + hours // 24) + set_hours (hours \\ 24) + Precursor {YMD_DURATION} + end + + add (other: like Current) + -- Add other to current. + do + Precursor {YMD_DURATION} (other) + Precursor {HMS_DURATION} (other) + end + + sub (other: like Current) + -- Subtract other from current. + do + Precursor {YMD_DURATION} (other) + Precursor {HMS_DURATION} (other) + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + -- Result is normalized. + local + v: DOUBLE + fract: DOUBLE + do + v := years * r + years := v.floor + fract := v - years + + v := months * r + 12 * fract + months := v.floor + fract := v - months + + v := days * r + days_per_month * fract + days := v.floor + fract := v - days + + v := hours * r + 24 * fract + hours := v.floor + fract := v - hours + + v := minutes * r + 60 * fract + minutes := v.floor + fract := v - minutes + + v := seconds * r + 60 * fract + seconds := v.rounded + normalize + end + + divide (r: DOUBLE) + -- Divide by 'r'. + -- Result is normalized. + do + Precursor {HMS_DURATION} (r) -- calculates based on seconds. + end + + div (i: INTEGER) + -- Integer division. + -- Result is normalized. + do + Precursor {HMS_DURATION} (i) -- calculates based on seconds. + end + + mod (i: INTEGER) + -- Modulo. + -- Result is normalized. + do + Precursor {HMS_DURATION} (i) -- calculates based on seconds. + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + do + Result := as_days / other.as_days -- Days seemed reasonable accuracy. + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Is this duration shorter than other? + do + Result := Precursor {YMD_DURATION} (other) or else + (years = other.years and then months = other.months and then days = other.days and then + Precursor {HMS_DURATION} (other)) + end + +feature {NONE} -- Implementation + + hours_per_year: DOUBLE + -- Number of hours in a year. + do + Result := days_per_year * 24 + end + + hours_per_month: DOUBLE + -- Number of hours in a month. + do + Result := days_per_month * 24 + end + + + +end -- class YMDHMS_DURATION + diff --git a/jj_temporal/classes/ymdhms_duration_constants.e b/jj_temporal/classes/ymdhms_duration_constants.e new file mode 100644 index 0000000..7773566 --- /dev/null +++ b/jj_temporal/classes/ymdhms_duration_constants.e @@ -0,0 +1,66 @@ +note + description: "[ + Constants for use with {YMDHMS_TIME}, {YMDHMS_DURATION}, + and {YMDHMS_INTERVAL}. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_DURATION_CONSTANTS + +feature -- Access + + One_second: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 0, 0, 0, 1) + end + + One_minute: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 0, 0, 1, 0) + end + + One_hour: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 0, 1, 0, 0) + end + + One_day: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 1, 0, 0, 0) + end + + One_week: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 7, 0, 0, 0) + end + + One_month: YMDHMS_DURATION + once + create Result + Result.set (0, 1, 0, 0, 0, 0) + end + + One_quarter: YMDHMS_DURATION + once + create Result + Result.set (0, 3, 0, 0, 0, 0) + end + + One_year: YMDHMS_DURATION + once + create Result + Result.set (1, 0, 0, 0, 0, 0) + end + +end -- class YMDHMS_DURATION_CONSTANTS diff --git a/jj_temporal/classes/ymdhms_interval.e b/jj_temporal/classes/ymdhms_interval.e new file mode 100644 index 0000000..bb617b9 --- /dev/null +++ b/jj_temporal/classes/ymdhms_interval.e @@ -0,0 +1,60 @@ +note + description: "[ + A span of time consisting of a start-time, finish-time + and duration described in terms of years, months, + days, hours, minutes, and seconds. Positive durations only. + ]" + names: "ymdhms_interval, interval, time_span, time_interval, span" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_INTERVAL + +inherit + + HMS_INTERVAL + undefine + default_create, + time_anchor, + duration_anchor + end + + YMD_INTERVAL + redefine + time_anchor, + duration_anchor + end + +create + default_create + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMDHMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMDHMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/classes/ymdhms_time.e b/jj_temporal/classes/ymdhms_time.e new file mode 100644 index 0000000..6e12d31 --- /dev/null +++ b/jj_temporal/classes/ymdhms_time.e @@ -0,0 +1,391 @@ +note + description: "[ + An exact point of time of a particular day. A Year, Month, Day, + Hour, Minute, Second - time (ie. a date and time). + ]" + names: "date, time, date_and_time" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_TIME + +inherit + + YMD_TIME + rename + set as set_ymd_time, + as_days as as_seconds, + from_days as from_seconds + redefine + default_create, + set_now, + set_now_utc, + set_now_utc_fine, + is_less, + is_valid, + add_duration, + time_between, +-- normalize, + truncate_to_years, + truncate_to_months, + as_string, + as_seconds, + from_seconds, + from_string, + is_valid_string_representation, + is_valid_integer_representation, + is_representable_as_integer, + duration_anchor, + interval_anchor + end + + HMS_TIME + rename + set as set_hms_time + redefine + default_create, + set_now, + set_now_utc, + set_now_fine, + set_now_utc_fine, + is_less, + is_valid, + add_duration, + time_between, + seconds_between, + add_hours, +-- normalize, + truncate_to_hours, + truncate_to_minutes, + as_string, + as_seconds, + from_seconds, + from_string, + is_valid_string_representation, + is_valid_integer_representation, + is_representable_as_integer, + Duration_anchor, + Interval_anchor + select + from_seconds + end + +create + default_create, + set_now, + set_now_utc, + set_now_fine, + set_now_utc_fine, + from_seconds, + from_string + +feature {NONE} -- Initialization + + default_create + -- Create an instance with todays date at midnight. + do + Precursor {HMS_TIME} + Precursor {YMD_TIME} + end + +feature -- Access + + as_string: STRING + -- String representation of Current in a compact form. + do + Result := Precursor {YMD_TIME} + Result.append ("T") + Result.append (Precursor {HMS_TIME}) + end + + as_seconds: INTEGER + -- The number of seconds from midnight (00:00:00) + -- on 1 Jan 1970 to the Current time. + local + days: INTEGER + do + days := Precursor {YMD_TIME} + Result := days * 24 * 60 * 60 + Precursor {HMS_TIME} + end + +feature -- Element Change + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + local + pos: INTEGER + do + pos := a_string.index_of ('T', 1) + Precursor {YMD_TIME} (a_string.substring (1, pos - 1)) + Precursor {HMS_TIME} (a_string.substring (pos + 1, a_string.count)) + end + + from_seconds (a_seconds: INTEGER) + -- Change Current to the time represented by `a_seconds'. + -- `A_seconds' is assumed to be the number of seconds since 1 Jan 1970. + -- It must represent a date that is not BC. + do + set (1970, 1, 1, 0, 0, 0) + add_seconds (a_seconds) + end + + set_now + -- Initialize the instance from the system clock unsing the + -- current time zone. + do + Precursor {HMS_TIME} + Precursor {YMD_TIME} + end + + set_now_utc + -- Initialize the instance from the system clock unsing GMT. + do + Precursor {HMS_TIME} + Precursor {YMD_TIME} + end + + set_now_fine + -- Initialize the instance from the system clock using the current + -- time zone and including milliseconds. + do + set_now + Precursor {HMS_TIME} + end + + set_now_utc_fine + -- Initialize the instance from the system clock using the GMT and + -- including milliseconds. + do + set_now_utc + Precursor {HMS_TIME} + end + + set (a_year, a_month, a_day, a_hour, a_minute, a_second: INTEGER) + -- Change the 'year', ..., 'second'. + require + year_valid: a_year /= 0; + month_valid: 1 <= a_month and a_month <= 12; + day_valid: 1 <= a_day and a_day <= 31; + hour_valid: 0 <= a_hour and a_hour <= 23; + minute_valid: 0 <= a_minute and a_minute <= 59; + second_valid: 0 <= a_second and a_second <= 59 + do + set_ymd_time (a_year, a_month, a_day); + set_hms_time (a_hour, a_minute, a_second); + end + + truncate_to_years + -- Set to midnight on the first day of month 1. + -- Use when all but the `year' is to be ignored. + do + Precursor {YMD_TIME} + set_hms_time (0, 0, 0) + ensure then + year_unchanged: year = old year + month_one: month = 1 + day_one: day = 1 + hour_zero: hour = 0 + minute_zero: minute = 0 + second_zero: second = 0 + end + + truncate_to_months + -- Set to midnight on the first day of the current month. + -- Use when all but the `year' and `month' is to be ignored. + do + Precursor {YMD_TIME} + set_hms_time (0, 0, 0) + ensure then + year_unchanged: year = old year + month_unchaged: month = old month + day_one: day = 1 + hour_zero: hour = 0 + minute_zero: minute = 0 + second_zero: second = 0 + end + + truncate_to_days + -- Set to midnight on the current day. + -- Use when the time portion of the date is to be ignored. + do + set_hms_time (0, 0, 0) + ensure then + year_unchanged: year = old year + month_unchaged: month = old month + day_unchaged: day = old day + hour_zero: hour = 0 + minute_zero: minute = 0 + second_zero: second = 0 + end + + truncate_to_hours + -- Set the `hour', `second', and `millisecond' to zero. + -- Used when these portions of the time are to be ignored. + do + set (year, month, day, hour, 0, 0) + end + + truncate_to_minutes + do + set (year, month, day, hour, minute, 0) + end + +feature -- Basic operations + + add_duration (a_duration: like duration_anchor) + -- Add a length of time (in years, months, days, + -- hours, minutes, and seconds) to the time. + do + Precursor {HMS_TIME} (a_duration) + add_days (overflow) + clear_overflow + Precursor {YMD_TIME} (a_duration) + ensure then + no_overflowing_days: overflow = 0 + end + + add_hours (a_number: INTEGER) + -- Add `a_number' of hours to the current time + do + Precursor {HMS_TIME} (a_number) + add_days (overflow) + clear_overflow + end + +feature -- Status report + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + do + Result := Precursor {HMS_TIME} and then Precursor {YMD_TIME} + end + +feature -- Querry + + time_between (other: like Current): like duration_anchor + -- The difference between two dates as a time span or duration. + local + larger, smaller: like Current + y, mon, d, h, m, s: INTEGER + do + larger := max (other) + smaller := min (other) + y := larger.year - smaller.year + mon := larger.month - smaller.month + d := larger.day - smaller.day + h := larger.hour - smaller.hour + m := larger.minute - smaller.minute + s := larger.second - smaller.second + if s < 0 then + s := s + 60 + m := m - 1 + end + if m < 0 then + m := m + 60 + h := h - 1 + end + if h < 0 then + h := h + 24 + d := d - 1 + end + if d < 0 then + d := d + smaller.last_day_of_month + mon := mon - 1 + end + if mon < 0 then + mon := mon + 12 + y := y - 1 + end + create Result + Result.set (y, mon, d, h, m, s) + if Current < other then + Result.negate + end + end + + seconds_between (a_other: like Current): INTEGER + -- The number of seconds between Current and `a_other'. + do + Result := days_between (a_other) * 24 * 60 * 60 + Precursor {HMS_TIME} (a_other) + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + local + i: INTEGER + ds, ts: STRING + do + if a_string /= Void then + i := a_string.index_of ('T', 1) + ds := a_string.substring (1, i - 1) + ts := a_string.substring (i + 1, a_string.count) + Result := Precursor {YMD_TIME} (ds) and then Precursor {HMS_TIME} (ts) + end + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in range to be converted to a time? + do + Result := Precursor {HMS_TIME} (a_integer) and then + Precursor {YMD_TIME} (a_integer) + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does this date_and_time come before 'other' + do + Result := year < other.year or else + ((year = other.year) and (month < other.month)) or else + ((year = other.year) and (month = other.month) and (day < other.day)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour < other.hour)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour = other.hour) and (minute < other.minute)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour = other.hour) and (minute = other.minute) and (second < other.second)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour = other.hour) and (minute = other.minute) and (second = other.second) and + (millisecond < other.millisecond)) + + end + +feature {NONE} -- Implementation + + is_valid: BOOLEAN + -- Is the date and time logical? + do + Result := Precursor {YMD_TIME} and Precursor {HMS_TIME} + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: YMDHMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: YMDHMS_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/classes/ymdhms_timer.e b/jj_temporal/classes/ymdhms_timer.e new file mode 100644 index 0000000..0198e06 --- /dev/null +++ b/jj_temporal/classes/ymdhms_timer.e @@ -0,0 +1,77 @@ +note + description: "Summary description for {YMDHMS_TIMER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + YMDHMS_TIMER + +inherit + + YMDHMS_INTERVAL + undefine + duration + redefine + default_create, + time_anchor, + duration_anchor + end + + HMS_TIMER + undefine + duration + redefine + default_create, + time_anchor, + duration_anchor + end + + YMD_TIMER + undefine + time_anchor, + duration_anchor + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Set up the timer + do + Precursor {YMDHMS_INTERVAL} + Precursor {YMD_TIMER} + create cumulative + end + + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMDHMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMDHMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + +end diff --git a/jj_temporal/demo/jj_temporal_demo.e b/jj_temporal/demo/jj_temporal_demo.e new file mode 100644 index 0000000..657efc8 --- /dev/null +++ b/jj_temporal/demo/jj_temporal_demo.e @@ -0,0 +1,88 @@ +note + description: "[ + Test objects for temporal cluster. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL: $" + date: "$Date: $" + revision: "$Revision: $" + +class + JJ_TEMPORAL_DEMO + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + local + i: INTEGER + do + create date + create time + create date_time + io.put_string (date.out) + io.new_line + io.new_line + io.put_string (time.out) + io.new_line + io.new_line + io.put_string (date_time.out) + + create ymd_formatter + create timer_1 + create timer_2 + timer_1.reset + timer_2.reset + + from i := 1 + until i > 10 + loop + io.put_string ("i = " + i.out + "%N") + timer_1.run + ee.sleep (100) + timer_1.stop + timer_2.run + ee.sleep (1_000_000_000) + timer_2.stop + io.put_string ("timer_1.cumulative = " + timer_1.cumulative.as_seconds.out) + io.new_line + io.put_string ("timer_2.cumulative = " + timer_2.cumulative.as_seconds.out) + io.new_line + i := i + 1 + end + io.put_string ("timer_1.cumulative = " + timer_1.cumulative.as_seconds.out) + io.put_string (" %T") + io.put_string ("timer_2.cumulative = " + timer_2.cumulative.as_seconds.out) + io.new_line + +-- io.put_string ("The formatted date = ") +-- io.put_string (ymd_formatter.to_string (date) + "%N") + end + +feature -- Access + + date: YMD_TIME + -- To test a date + + time: HMS_TIME + -- To test a time + + date_time: YMDHMS_TIME + -- To test a date and time + + ymd_formatter: YMD_TIME_FORMATTER + -- To test the gobo parsers + + timer_1, timer_2: HMS_TIMER + + ee: EXECUTION_ENVIRONMENT + once + create Result + end + +end diff --git a/jj_temporal/demo/jj_temporal_demo.ecf b/jj_temporal/demo/jj_temporal_demo.ecf new file mode 100644 index 0000000..6cf836d --- /dev/null +++ b/jj_temporal/demo/jj_temporal_demo.ecf @@ -0,0 +1,23 @@ + + + + + + + + + + + + /.git$ + /.svn$ + /CVS$ + /EIFGENs$ + + + + diff --git a/jj_temporal/docs/Forum.txt b/jj_temporal/docs/Forum.txt new file mode 100644 index 0000000..0bf6d0b --- /dev/null +++ b/jj_temporal/docs/Forum.txt @@ -0,0 +1,18 @@ +Eiffel Forum License, version 2 + +1. Permission is hereby granted to use, copy, modify and/or + distribute this package, provided that: + * copyright notices are retained unchanged, + * any distribution of this package, whether modified or not, + includes this license text. +2. Permission is hereby also granted to distribute binary programs + which depend on this package. If the binary program depends on a + modified version of this package, you are encouraged to publicly + release the modified version of this package. + +THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE. diff --git a/jj_temporal/docs/main_classes.png b/jj_temporal/docs/main_classes.png new file mode 100644 index 0000000..dd2531c Binary files /dev/null and b/jj_temporal/docs/main_classes.png differ diff --git a/jj_temporal/formatters/hms_duration_formatter.e b/jj_temporal/formatters/hms_duration_formatter.e new file mode 100644 index 0000000..3c4dba5 --- /dev/null +++ b/jj_temporal/formatters/hms_duration_formatter.e @@ -0,0 +1,192 @@ +note + description: "[ + Utility class for converting {HMS_DURATION}'s to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a duration in feature `to_hms_duration' is more + relaxed. + ]" + date: "18 Feb 03" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_DURATION_FORMATTER + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + set_separator (", ") + set_hour_minute_second + end + +feature -- Access + + separator: STRING + +feature -- Element change + + set_separator (a_string: STRING) + require + string_exists: a_string /= Void + do + separator := a_string + end + + set_hour_minute_second + -- Set format to day-month-year. + do + format := hms + end + + set_second_minute_hour + do + format := smh + end + + set_hour_minute + do + format := hm + end + + set_minute_hour + do + format := mh + end + +feature -- Access + + hour_string (a_duration: HMS_DURATION): STRING + do + create Result.make(8) + Result.append_integer (a_duration.hours) + Result.append (" hour") + if a_duration.hours /= 1 and a_duration.hours /= -1 then + Result.append ("s") + end + end + + minute_string (a_duration: HMS_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.minutes) + Result.append (" minute") + if a_duration.minutes /= 1 and a_duration.minutes /= -1 then + Result.append ("s") + end + end + + second_string (a_duration: HMS_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.seconds) + Result.append (" second") + if a_duration.seconds /= 1 and a_duration.seconds /= -1 then + Result.append ("s") + end + end + + to_string (a_duration: HMS_DURATION): STRING + -- the whole duration as a string + do + create Result.make (20) + Result.append (hour_string(a_duration)) + Result.append (separator) + Result.append (minute_string(a_duration)) + Result.append (separator) + Result.append (second_string(a_duration)) + end + + string_to_duration (a_string: STRING): HMS_DURATION + -- Parse the string based on the current formatting. + require + valid_date_string: is_valid_duration_string (a_string) + do + check + fix_me: False then + end + end + +feature -- Query + + is_valid_duration_string (a_string: STRING): BOOLEAN + require + string_exists: a_string /= Void + do + -- parse the string + Result := True +-- !!! temporary + end + + is_index_in_hour_string (a_date: HMS_DURATION; a_index: INTEGER): BOOLEAN + require + date_exists: a_date /= Void +-- index_large_enough: a_index >= 1 + local + s, ds: STRING + i: INTEGER + do + s := to_string (a_date) + ds := hour_string (a_date) + i := s.substring_index (ds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ds.count-1 + end + end + + is_index_in_minute_string (a_date: HMS_DURATION; a_index: INTEGER): BOOLEAN + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_date) + ms := minute_string (a_date) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_second_string (a_date: HMS_DURATION; a_index: INTEGER): BOOLEAN + local + s, ys: STRING + i: INTEGER + do + s := to_string (a_date) + ys := second_string (a_date) + i := s.substring_index (ys, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ys.count-1 + end + end + +feature {NONE} -- Implementation + + format: INTEGER + + hms, smh, -- hours-minutes-seconds, etc + hm, mh : INTEGER = unique -- hours-minutes only + + hms_parse (a_string: STRING) + do + end + + +end -- class HMS_DURATION_FORMATTER + + diff --git a/jj_temporal/formatters/hms_time_formatter.e b/jj_temporal/formatters/hms_time_formatter.e new file mode 100644 index 0000000..104d4f8 --- /dev/null +++ b/jj_temporal/formatters/hms_time_formatter.e @@ -0,0 +1,245 @@ +note + description: "[ + Utility class for converting {HMS_TIME}'s to and from + strings based on a selected `format'. While the string given + by feature `to_string' is set based on the format, the parsing + of a string to a duration in feature `to_hms_time' is more + relaxed. + ]" + date: "18 Feb 03" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_TIME_FORMATTER + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature -- Initialization + + default_create + do + set_separator (":") + hide_seconds + set_12_hour + end + +feature -- Element change + + set_separator (a_string: STRING) + require + separator_exists: a_string /= Void + do + separator := a_string + end + + set_12_hour + do + is_12_hour := True + end + + set_24_hour + do + is_12_hour := False + end + + show_seconds + do + is_seconds_shown := True + end + + hide_seconds + do + is_seconds_shown := False + end + +feature -- Access + + separator: STRING + + hour_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + local + h: INTEGER + do + h := a_time.hour + if is_12_hour and then h >= 12 then + h := h - 12 + end + if is_12_hour and then h = 0 then + h := 12 + end + create Result.make(2) + if h < 10 then + Result.append ("0") + end + Result.append_integer (h) + end + + minute_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + do + create Result.make(2) + if a_time.minute < 10 then + Result.append ("0") + end + Result.append_integer (a_time.minute) + end + + second_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + do + create Result.make(2) + if a_time.second < 10 then + Result.append ("0") + end + Result.append_integer (a_time.second) + end + + am_pm_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + do + create Result.make (3) + if a_time.hour >= 12 then + Result.append (" PM") + else + Result.append (" AM") + end + end + + to_string (a_time: like time_anchor): STRING + -- the whole {HMS_TIME} as a string + require + time_exists: a_time /= Void + do + create Result.make (20) + Result.append (hour_string (a_time)) + Result.append (separator) + Result.append (minute_string (a_time)) + if is_seconds_shown then + Result.append (separator) + Result.append (second_string (a_time)) + end + if is_12_hour then + Result.append (am_pm_string (a_time)) + end + end + +feature -- Status report + + is_12_hour: BOOLEAN + + is_seconds_shown: BOOLEAN + +feature -- Query + + is_valid_time_string (a_time: STRING): BOOLEAN + require + string_exists: a_time /= Void + do + -- parse the string + end + + is_index_in_hour_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, hs: STRING + i: INTEGER + do + s := to_string (a_time) + hs := hour_string (a_time) + i := s.substring_index (hs, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + hs.count-1 + end + end + + is_index_in_minute_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_time) + ms := minute_string (a_time) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_second_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ss: STRING + i: INTEGER + do + s := to_string (a_time) + ss := hour_string (a_time) + i := s.substring_index (ss, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ss.count-1 + end + end + + is_index_in_am_pm_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ss: STRING + i: INTEGER + do + s := to_string (a_time) + ss := am_pm_string (a_time) + i := s.substring_index (ss, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ss.count-1 + end + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: HMS_TIME + -- Not to be called; just used to anchor types. + require + not_callable: False + do + check + do_not_call: False then + -- Because gives no info; simply used as anchor. + end + end + +feature {NONE} -- Implementation + + hms_parse (a_string: STRING) + do + end + + +end + + diff --git a/jj_temporal/formatters/ymd_duration_formatter.e b/jj_temporal/formatters/ymd_duration_formatter.e new file mode 100644 index 0000000..3986a09 --- /dev/null +++ b/jj_temporal/formatters/ymd_duration_formatter.e @@ -0,0 +1,192 @@ +note + description: "[ + Utility class for converting {YMD_DURATION}'s to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a duration in feature `to_ymd_duration' is more + relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_DURATION_FORMATTER + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + set_separator (", ") + set_year_month_day + end + +feature -- Access + + separator: STRING + +feature -- Element change + + set_separator (a_string: STRING) + require + string_exists: a_string /= Void + do + separator := a_string + end + + set_day_month_year + -- Set format to day-month-year. + do + format := dmy + end + + set_year_month_day + do + format := ymd + end + + set_day_month + do + format := dm + end + + set_month_year + do + format := my + end + +feature -- Access + + year_string (a_duration: YMD_DURATION): STRING + do + create Result.make(8) + Result.append_integer (a_duration.years) + Result.append (" year") + if a_duration.years /= 1 and a_duration.years /= -1 then + Result.append ("s") + end + end + + month_string (a_duration: YMD_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.months) + Result.append (" month") + if a_duration.months /= 1 and a_duration.months /= -1 then + Result.append ("s") + end + end + + day_string (a_duration: YMD_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.days) + Result.append (" day") + if a_duration.days /= 1 and a_duration.days /= -1 then + Result.append ("s") + end + end + + to_string (a_duration: YMD_DURATION): STRING + -- the whole duration as a string + do + create Result.make (20) + Result.append (day_string(a_duration)) + Result.append (separator) + Result.append (month_string(a_duration)) + Result.append (separator) + Result.append (year_string(a_duration)) + end + + string_to_duration (a_string: STRING): YMD_DURATION + -- Parse the string based on the current formatting. + require + valid_date_string: is_valid_date_string (a_string) + do + check + fix_me: False then + end + end + +feature -- Query + + is_valid_date_string (a_string: STRING): BOOLEAN + require + string_exists: a_string /= Void + do + -- parse the string + Result := True +-- !!! temporary + end + + is_index_in_day_string (a_date: YMD_DURATION; a_index: INTEGER): BOOLEAN + require + date_exists: a_date /= Void +-- index_large_enough: a_index >= 1 + local + s, ds: STRING + i: INTEGER + do + s := to_string (a_date) + ds := day_string (a_date) + i := s.substring_index (ds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ds.count-1 + end + end + + is_index_in_month_string (a_date: YMD_DURATION; a_index: INTEGER): BOOLEAN + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_date) + ms := month_string (a_date) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_year_string (a_date: YMD_DURATION; a_index: INTEGER): BOOLEAN + local + s, ys: STRING + i: INTEGER + do + s := to_string (a_date) + ys := year_string (a_date) + i := s.substring_index (ys, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ys.count-1 + end + end + + +feature {NONE} -- Implementation + + format: INTEGER + + dmy, ymd, -- day-month-year, etc + dm, my : INTEGER = unique -- day-month or month-year only + + dmy_parse (a_string: STRING) + do + end + + +end -- class YMD_DURATION_FORMATTER + + diff --git a/jj_temporal/formatters/ymd_time_format_constants.e b/jj_temporal/formatters/ymd_time_format_constants.e new file mode 100644 index 0000000..7a30d69 --- /dev/null +++ b/jj_temporal/formatters/ymd_time_format_constants.e @@ -0,0 +1,133 @@ +note + description: "[ + Constants describing how {YMD_TIME}'s (dates) should appear. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME_FORMAT_CONSTANTS + +feature -- Assess + + Day_month_year: INTEGER = 0 + -- (e.g. "31 January 2004" or "31/01/04") + + Year_month_day: INTEGER = 1 + -- (e.g. "2004 January 31" or "04/01/31") + + Month_day_year: INTEGER = 2 + -- (e.g. "January 31, 2004" or "01/31/04") + + Day_month: INTEGER = 3 + -- (e.g. "31 January" or "31/01") + + Month_year: INTEGER = 4 + -- (e.g. "January 2004" or "01/04") + + days_text: LINKED_LIST [STRING] + once + create Result.make + Result.extend ("SUN") + Result.extend ("MON") + Result.extend ("TUE") + Result.extend ("WED") + Result.extend ("THU") + Result.extend ("FRI") + Result.extend ("SAT") + Result.compare_objects + end + + months_text: LINKED_LIST [STRING] + once + create Result.make + Result.extend ("JAN") + Result.extend ("FEB") + Result.extend ("MAR") + Result.extend ("APR") + Result.extend ("MAY") + Result.extend ("JUN") + Result.extend ("JUL") + Result.extend ("AUG") + Result.extend ("SEP") + Result.extend ("OCT") + Result.extend ("NOV") + Result.extend ("DEC") + Result.compare_objects + end + + long_days_text: LINKED_LIST [STRING] + once + create Result.make + Result.extend ("SUNDAY") + Result.extend ("MONDAY") + Result.extend ("TUESDAY") + Result.extend ("WEDNESDAY") + Result.extend ("THURSDAY") + Result.extend ("FRIDAY") + Result.extend ("SATURDAY") + Result.compare_objects + end + + long_months_text: LINKED_LIST [STRING] + -- + once + create Result.make + Result.extend ("JANUARY") + Result.extend ("FEBRUARY") + Result.extend ("MARCH") + Result.extend ("APRIL") + Result.extend ("MAY") + Result.extend ("JUNE") + Result.extend ("JULY") + Result.extend ("AUGUST") + Result.extend ("SEPTEMBER") + Result.extend ("OCTOBER") + Result.extend ("NOVEMBER") + Result.extend ("DECEMBER") + Result.compare_objects + end + +feature -- Querry + + is_valid_format (a_integer: INTEGER): BOOLEAN + -- Does `a_integer' represent a valid date format? + do + Result := a_integer = Day_month_year or else + a_integer = Year_month_day or else + a_integer = Month_day_year or else + a_integer = Day_month or else + a_integer = Month_year + end + + is_month (a_string: STRING): BOOLEAN + -- Does a_string represent a month? + do + Result := months_text.has (a_string.as_upper) or else + long_months_text.has (a_string.as_upper) + end + + is_weekday (a_string: STRING): BOOLEAN + -- Does `a_string' represent a weekday? + do + Result := days_text.has (a_string.as_upper) or else + long_days_text.has (a_string.as_upper) + end + + get_month (a_month: STRING): INTEGER + -- Number of the `a_month' + require + is_month: is_month (a_month) + do + if months_text.has (a_month.as_upper) then + Result := months_text.index_of (a_month.as_upper, 1) + else + Result := long_months_text.index_of (a_month.as_upper, 1) + end + end + +end diff --git a/jj_temporal/formatters/ymd_time_formatter.e b/jj_temporal/formatters/ymd_time_formatter.e new file mode 100644 index 0000000..3807521 --- /dev/null +++ b/jj_temporal/formatters/ymd_time_formatter.e @@ -0,0 +1,397 @@ +note + description: "[ + Utility class for converting {YMD_TIME}'s (i.e. dates) to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a date in feature `to_ymd_time' is more relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME_FORMATTER + +inherit + + YMD_TIME_FORMAT_CONSTANTS + redefine + default_create + end + +create + default_create + +feature -- Initialization + + default_create + -- Create an instance to parse dates in "dd mmm yy" format. + do + set_separator (" ") + end + +feature -- Access + + separator: STRING + -- The character (or string) placed between the day, month, year, etc. + + to_ymd_time (a_string: STRING): like time_anchor + -- Parse `a_string' + require + string_exists: a_string /= Void + is_string_valid: is_valid (a_string) + do + Result := parsed (a_string) + ensure + result_exists: Result /= Void + end + + to_string (a_ymd_time: like time_anchor): STRING + -- The complete string representation of `a_ymd_time'. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (20) + inspect format + when Day_month_year then + if is_weekday_included then + Result.append (weekday_string (a_ymd_time)) + Result.append (", ") + end + Result.append (day_string (a_ymd_time)) + Result.append (separator) + Result.append (month_string (a_ymd_time)) + Result.append (separator) + Result.append (year_string (a_ymd_time)) + when Year_month_day then + when Month_day_year then + when Month_year then + when Day_month then + else + check + should_not_happen: False + -- because format must be one of these + end + end + end + + year_string (a_ymd_time: like time_anchor): STRING + -- The string representation of `year' feature of `a_ymd_time'. + -- Will be shortened to two characters if `is_short_format'. + do + create Result.make(4) + Result.append_integer (a_ymd_time.year) + if is_short_format then + if a_ymd_time.year < 10 then + Result.keep_tail (1) + if is_zero_padded then + Result.prepend ("0") + end + else + Result.keep_tail (2) + end + else + if is_zero_padded then + if a_ymd_time.year < 10 then + Result.prepend ("000") + elseif a_ymd_time.year < 100 then + Result.prepend ("00") + elseif a_ymd_time.year < 1000 then + Result.prepend ("0") + end + end + end + ensure + valid_length_if_short: is_short_format implies Result.count <= 2 + end + + month_string (a_ymd_time: like time_anchor): STRING + -- The string representation of `month' feature of `a_ymd_time'. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (10) + if is_month_numeric then + if is_zero_padded and a_ymd_time.month < 10 then + Result.append ("0") + end + Result.append_integer (a_ymd_time.month) + else + if is_short_format then + Result.append (months_text.i_th (a_ymd_time.month)) + else + Result.append (long_months_text.i_th (a_ymd_time.month)) + end + end + end + + day_string (a_ymd_time: like time_anchor): STRING + -- The string representation of `day' feature of `a_ymd_time'. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (2) + if is_zero_padded and a_ymd_time.day < 10 then + Result.append ("0") + end + Result.append_integer (a_ymd_time.day) + end + + weekday_string (a_ymd_time: like time_anchor): STRING + -- The string repesentation of the `weekday' of `a_ymd_time'. + -- (i.e. "Sunday", "Monday, etc. or "Sun", "Mon", etc. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (15) + inspect a_ymd_time.weekday + when 1 then Result.append ("Sunday") + when 2 then Result.append ("Monday") + when 3 then Result.append ("Tuesday") + when 4 then Result.append ("Wednesday") + when 5 then Result.append ("Thursday") + when 6 then Result.append ("Friday") + when 7 then Result.append ("Saturday") + else + check + should_not_happen: False + -- because `weekday' ranges from 1 to 7. + end + end + if is_short_format then + Result.keep_head (3) + end + end + +feature -- Element change + + set_separator (a_string: STRING) + -- Set `separator' to `a_string'. + require + separator_exists: a_string /= Void + do + separator := a_string + ensure + seperator_set: separator = a_string + end + + set_format (a_format: INTEGER) + -- Change `format'. + -- The values are in YMD_TIME_FORMAT_CONSTANTS + require + valid_format: is_valid_format (a_format) + do + format := a_format + end + + set_show_weekday + -- Include the day of the week in the output string. + do + is_weekday_included := True + end + + set_hide_weekday + -- Do not include the day of the week in the output string. + do + is_weekday_included := False + end + + set_format_short + -- Abriviate the `month_string' (if shown as text) to three + -- characters and shorten the year to two digits. + do + is_short_format := True + end + + set_format_long + -- Show the `month_string' (if shown as text) to the complete + -- (unabriviated) word and show the year as four digits. + do + is_short_format := False + end + + set_month_numeric + -- Make the month appear as digits, not text. + do + is_month_numeric := True + ensure + showing_month_as_digits: is_month_numeric + end + + set_month_text + -- Make the month appear as text. + -- It may be full text or abbriviated depending on `is_format_short'. + do + is_month_numeric := False + ensure + showing_month_as_text: not is_month_numeric + end + + set_pad_zeros + -- Make sure the `day_string', `year_string', and `month_string' (when + -- `is_month_numeric') are padded with leading zeros when necessary. + -- For example, in numeric form "9 Jan 2004" may be shown as "09/01/04". + do + is_zero_padded := True + ensure + zero_padding_set: is_zero_padded + end + + set_hide_zeros + -- Do not pad numeric values with leading zeros. + do + is_zero_padded := False + ensure + not_padded: not is_zero_padded + end + +feature -- Basic operations + + save_format + -- Save the `format' for restoration later. + do + saved := format + ensure + format_saved: saved = format + end + + restore_format + -- Reset `format' to the value `saved' by a call to `save_format'. + do + format := saved + ensure + format_restored: format = saved + end + +feature -- Query + + is_valid (a_string: STRING): BOOLEAN + -- Is `a_string' convertable to a date? + require + string_exists: a_string /= Void + do + Result := parsed (a_string) /= Void + ensure + definition: Result implies parsed (a_string) /= Void + end + + is_weekday_included: BOOLEAN + -- Is the day of week (ie "Monday") in ymd_time string. + + is_short_format: BOOLEAN + -- Is the year two digits instead of four and + -- is the month abriviated? + + is_month_numeric: BOOLEAN + -- Is the `month_string' shown as digits? (As opposed to a + -- textual representation such as "January".) + + is_zero_padded: BOOLEAN + -- Are digital values to be padded with leading zero's if + -- shorter than normal? + + is_index_in_day_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + ymd_time_exists: a_ymd_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ds: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + ds := day_string (a_ymd_time) + i := s.substring_index (ds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ds.count-1 + end + end + + is_index_in_month_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + ymd_time_exists: a_ymd_time /= Void + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + ms := month_string (a_ymd_time) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_year_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + local + s, ys: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + ys := year_string (a_ymd_time) + i := s.substring_index (ys, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ys.count-1 + end + end + + is_index_in_weekday_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + local + s, wds: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + wds := weekday_string (a_ymd_time) + i := s.substring_index (wds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + wds.count-1 + end + end + +feature {NONE} -- Implementation + + parsed (a_string: STRING): like time_anchor + -- Attemp to convert `a_string' to a {YMD_TIME}, returning + -- Void if unable. + require + string_exists: a_string /= Void + string_has_length: a_string.count >= 1 + local + p: YMD_TIME_PARSER + do + create p +-- p.set_format (format) +-- p.parse_string (a_string) +-- Result := p.last_value + check + fix_me: False then + end + end + + format: INTEGER + + saved: INTEGER + -- used to save the format. + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMD_TIME + -- Not to be called; just used to anchor types. + require + not_callable: False + do + check + do_not_call: False then + -- Because gives no info; simply used as anchor. + end + end + +invariant + + valid_ymd_time_format: is_valid_format (format) + +end + + diff --git a/jj_temporal/formatters/ymdhms_duration_formatter.e b/jj_temporal/formatters/ymdhms_duration_formatter.e new file mode 100644 index 0000000..3a6dcb2 --- /dev/null +++ b/jj_temporal/formatters/ymdhms_duration_formatter.e @@ -0,0 +1,68 @@ +note + description: "[ + Utility class for converting {YMDHMS_DURATION}'s to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a date in feature `to_ymdhms_duration' is more + relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_DURATION_FORMATTER + +inherit + + HMS_DURATION_FORMATTER + rename + to_string as time_string, + set_separator as set_time_separator, + separator as time_separator, + string_to_duration as hms_string_to_duration, + format as hms_format + redefine + default_create + end + + YMD_DURATION_FORMATTER + rename + to_string as date_string, + set_separator as set_date_separator, + separator as date_separator, + string_to_duration as ymd_string_to_duration, + format as ymd_format + redefine + default_create + end + +create + default_create + +feature -- Initialization + + default_create + -- + do + Precursor {HMS_DURATION_FORMATTER} + Precursor {YMD_DURATION_FORMATTER} + end + +feature -- Access + + to_string (a_duration: YMDHMS_DURATION): STRING + -- the whole duration as a string + require + duration_exists: a_duration /= Void + do + create Result.make (30) + Result.append (date_string (a_duration)) + Result.append (" ") + Result.append (time_string (a_duration)) + end + +end -- class YMDHMS_DURATION_FORMATTER diff --git a/jj_temporal/formatters/ymdhms_time_formatter.e b/jj_temporal/formatters/ymdhms_time_formatter.e new file mode 100644 index 0000000..1fd19aa --- /dev/null +++ b/jj_temporal/formatters/ymdhms_time_formatter.e @@ -0,0 +1,126 @@ +note + description: "[ + Utility class for converting {YMDHMS_TIME}'s (i.e. date/times) to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a date in feature `to_ymd_time' is more relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_TIME_FORMATTER + +inherit + + HMS_TIME_FORMATTER + rename + set_separator as set_time_separator, + separator as time_separator + redefine + default_create, + to_string, + time_anchor + end + + YMD_TIME_FORMATTER + rename + set_separator as set_date_separator, + separator as date_separator + redefine + default_create, + to_string, + time_anchor + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + Precursor {HMS_TIME_FORMATTER} + Precursor {YMD_TIME_FORMATTER} + end + +feature -- Access + + to_string (a_time: like time_anchor): STRING + -- the whole date as a string + do + create Result.make (30) + if not is_date_hidden then + Result.append (Precursor {YMD_TIME_FORMATTER} (a_time)) + Result.append (" ") + end + if not is_time_hidden then + Result.append (Precursor {HMS_TIME_FORMATTER} (a_time)) + end + end + +feature -- Status report + + is_time_hidden: BOOLEAN + -- Will `to_string' not include the time? + + is_date_hidden: BOOLEAN + -- Will `to_string' not include the date? + +feature -- Status setting + + hide_time + -- Make `to_string' produce a string showing the date only; + -- the time portion will not show. + do + is_time_hidden := True + is_date_hidden := False + ensure + time_is_hidden: is_time_hidden + date_is_shown: not is_date_hidden + end + + hide_date + -- Make `a_string' produce a string showing the time only; + -- the date portionn will not show. + do + is_date_hidden := True + is_time_hidden := False + ensure + date_is_hidden: is_date_hidden + time_is_shown: not is_time_hidden + end + + show_date_and_time + -- Make `to_string' produce a string showing both the date + -- portion and the time portion. This is the default. + do + is_date_hidden := False + is_time_hidden := False + ensure + date_is_shown: not is_date_hidden + time_is_shown: not is_time_hidden + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMDHMS_TIME + -- Not to be called; just used to anchor types. + require else + not_callable: False + do + check + do_not_call: False then + -- Because gives no info; simply used as anchor. + end + end + +invariant + + not_both_date_and_time_hidden: not (is_date_hidden and is_time_hidden) + +end diff --git a/jj_temporal/jj_t/README.md b/jj_temporal/jj_t/README.md new file mode 100644 index 0000000..d69b0e4 --- /dev/null +++ b/jj_temporal/jj_t/README.md @@ -0,0 +1,7 @@ +# jj_temporal +Eiffel date and time classes + +Main classes: ![](docs/main_classes.png?raw=true) + + + diff --git a/jj_temporal/jj_t/classes/abstract_duration.e b/jj_temporal/jj_t/classes/abstract_duration.e new file mode 100644 index 0000000..df14a88 --- /dev/null +++ b/jj_temporal/jj_t/classes/abstract_duration.e @@ -0,0 +1,229 @@ +note + description: "[ + Notion of a duration of time such as 2 hours, or 3 years, etc. + ]" + names: "abstract_duration, duration" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + ABSTRACT_DURATION + +inherit + COMPARABLE + +feature -- Access + +feature -- Access + + as_string: STRING + -- The time represented as a string, ideally with not extra characters. + deferred + end + + negative: like Current + -- The negative value of this duration + do + Result := twin + Result.negate + ensure + negative_result: Current > zero implies Result < zero + positive_result: Current < zero implies Result > zero + end + + one: like Current + -- Neutral element for "*" and "/" + deferred + ensure + result_exists: Result /= Void + valid_result: Result.is_one + end + + zero: like Current + -- Neutral element for "+" and "-" + deferred + ensure + result_exists: Result /= Void + good_result: Result.is_zero + end + +feature -- Status Report + + is_zero: BOOLEAN + -- Is this duration of 0 length? + do + Result := equal (Current, zero) + ensure + valid_result: Result implies equal (Current, zero) + end + + is_one: BOOLEAN + -- Is this duration neutral for '*' and '/'? + do + Result := equal (Current, one) + ensure + valid_result: Result implies equal (Current, one) + end + + is_negative: BOOLEAN + -- Is current less than the 'zero' duration? + do + Result := Current < zero + ensure + valid_result: Result implies Current < zero + end + +feature -- Element Change + + set_zero + -- Make the duration have zero length. + deferred + ensure + is_zero: is_zero + end + + + negate + -- Reverses the sign. + deferred + ensure + positive_implication: not is_negative implies old is_negative + negative_implication: is_negative implies not old is_negative + end + + add (other: like Current) + -- Add other other to Current. + require + other_exists: other /= Void + deferred + end + + sub (other: like Current) + -- Subtract other from Current + require + other_exists: other /= Void + deferred + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + deferred + end + + divide (r: DOUBLE) + -- Divide by 'r'. + require + not_zero_devisor: r /= 0 + deferred + end + + div (i: INTEGER) + -- Integer division. + require + not_zero_devisor: i /= 0 + deferred + end + + mod (i: INTEGER) + -- Modulo. + require + not_zero_devisor: i /= 0 + deferred + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + -- For example: is current duration at least twice as long as other? + require + other_exists: other /= Void + other_not_zero: not other.is_zero + deferred + end + +feature -- Basic operations + + identity alias "+": like Current + -- Just a clone of Current. Included for symetry. + do + Result := twin + ensure + no_side_effect: equal (Current, old Current) + end + + oposite alias "-": like Current + -- Invert the sign of other. + do + Result := twin + Result.negate + ensure + no_side_effect: equal (Current, old Current) + end + + plus alias "+" (other: like Current): like Current + -- Sum of current and other. + do + Result := twin + Result.add (other) + ensure + no_side_effect: equal (Current, old Current) + end + + minus alias "-" (other: like Current): like Current + -- Difference of Current and other. + do + Result := twin + Result.sub (other) + ensure + no_side_effect: equal (Current, old Current) + end + + product alias "*" (r: DOUBLE): like Current + -- Product of Current and 'r'. + -- Multiply by a factor of 'r'. + do + Result := twin + Result.multiply (r) + ensure + no_side_effect: equal (Current, old Current) + end + + quotient alias "/" (r: DOUBLE): like Current + -- Quotent of Current by 'r'. + require + not_zero_devisor: r /= 0 + do + Result := twin + Result.divide (r) + ensure + no_side_effect: equal (Current, old Current) + end + + integer_quotient alias "//" (i: INTEGER): like Current + -- Integer division of Current by 'i'. + require + not_zero_devisor: i /= 0 + do + Result := twin + Result.div (i) + ensure + no_side_effect: equal (Current, old Current) + end + + integer_remainder alias "\\" (i: INTEGER): like Current + -- Modulo of Current by 'i'. + require + not_zero_devisor: i /= 0 + do + Result := twin + Result.mod (i) + ensure + no_side_effect: equal (Current, old Current) + end + +end + diff --git a/jj_temporal/jj_t/classes/abstract_interval.e b/jj_temporal/jj_t/classes/abstract_interval.e new file mode 100644 index 0000000..82c074c --- /dev/null +++ b/jj_temporal/jj_t/classes/abstract_interval.e @@ -0,0 +1,387 @@ +note + description: "[ + Notion of a span of time consisting of a start-time, a + finish-time and a duration. Positive durations only. + ]" + names: "abstract_interval, time_span, time_interval, span" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + ABSTRACT_INTERVAL + +inherit + + COMPARABLE + undefine + default_create + end + +feature -- Access + + start: like time_anchor + -- Beginning moment of the time span and anchor for class. + do + Result := start_imp.twin + ensure + result_exists: Result /= Void + end + + finish: like time_anchor + -- Ending moment of the time span. + do + Result := finish_imp.twin + ensure + result_exists: Result /= Void + end + + duration: like duration_anchor + -- Length of time span. + do + Result := finish.time_between (start) + ensure + result_exists: Result /= Void + end + +feature -- Element Change + + set_start_finish (a_start_time, a_finish_time: like time_anchor) + -- Set the `start' and `finish' times. + require + times_exists: a_start_time /= Void and a_finish_time /= Void + valid_times: a_start_time <= a_finish_time + do + start_imp := a_start_time.twin + finish_imp := a_finish_time.twin + ensure + start_was_set: equal (start, a_start_time) + finish_was_set: equal (finish, a_finish_time) + end + + set_start_duration (a_start_time: like time_anchor; a_duration: like duration_anchor) + -- Set the `start' time and the `duration'. + require + start_time_exists: a_start_time /= Void + duration_exists: a_duration /= Void + positive_duration: not a_duration.is_negative + do + start_imp := a_start_time.twin + finish_imp := a_start_time + a_duration + ensure + start_was_set: equal (start, a_start_time) + duration_was_set: equal (duration, a_duration) + end + + set_duration_finish (a_duration: like duration_anchor; a_finish_time: like time_anchor) + -- Set the `duration' and `finish' time. + require + duration_exists: a_duration /= Void + positive_duration: not a_duration.is_negative + finish_time_exists: a_finish_time /= Void + do + start_imp := a_finish_time - a_duration + finish_imp := a_finish_time.twin + ensure + finish_was_set: equal (finish, a_finish_time) + duration_was_set: equal (duration, a_duration) + end + + move (a_duration: like duration_anchor) + -- Change the `start' and `finish' times by moving the + -- interval by the amount represented by `a_duration'. + require + duration_exists: a_duration /= Void + do + start_imp.add_duration (a_duration) + finish_imp.add_duration (a_duration) + ensure + duration_unchanged: equal (duration, old duration) + end + +feature -- Status Report + + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does current interval start before other or if they start at the + -- same time, does Current end before the other? + do + if (start < other.start) or else + (start.is_equal (other.start) and then finish < other.finish) then + Result := true + end + ensure then + less_than_definition: Result implies (start < other.start or else + (start.is_equal (other.start) and then finish < other.finish)) + end + + meets (other: like Current): BOOLEAN + -- x.meets(y) |-----x----->| + -- y.is_met_by(x) |-----y----->| + require + other_exists: other /= Void + do + Result := equal (finish, other.start) + ensure + Result implies equal (finish, other.start) + Result implies Current < other + end + + is_met_by (other: like Current): BOOLEAN + -- x.meets(y) |-----x----->| + -- y.is_met_by(x) |-----y----->| + require + other_exists: other /= Void + do + Result := equal (start, other.finish) + ensure + Result implies equal (start, other.finish) + Result implies other < Current + end + + is_before (other: like Current): BOOLEAN + -- x.is_before(y) |-----x----->| + -- y.is_after(x) |-----y----->| + require + other_exists: other /= Void + do + Result := finish < other.start + ensure + Result implies finish.is_before (other) + Result implies Current < other + end + + is_after (other: like Current): BOOLEAN + -- x.is_before(y) |-----x----->| + -- y.is_after(x) |-----y----->| + require + other_exists: other /= Void + do + Result := start > other.finish + ensure + Result implies start.is_after (other) + Result implies other < Current + end + + includes (other: like Current): BOOLEAN + -- x.includes(y) |-----x----->| + -- y.is_included_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := other.start.belongs (Current) and + other.finish.belongs (Current) + ensure + Result implies other.start.belongs (Current); + Result implies other.finish.belongs (Current) + end + + is_included_by (other: like Current): BOOLEAN + -- x.includes(y) |-----x----->| + -- y.is_included_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := start.belongs (other) and finish.belongs (other) + ensure + Result implies start.belongs (other); + Result implies finish.belongs (other); + end + + overlaps (other: like Current): BOOLEAN + -- x.overlaps(y) |-----x----->| + -- y.is_overlapped_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := finish.belongs (other) + ensure + Result implies finish.belongs (other) + end + + is_overlapped_by (other: like Current): BOOLEAN + -- x.overlaps(y) |-----x----->| + -- y.is_overlapped_by(x) |--y-->| + require + other_exists: other /= Void + do + Result := other.finish.belongs (Current) + ensure + Result implies other.finish.belongs (Current) + end + + intersects (other: like Current): BOOLEAN + -- Do the two intervals have a least one time point in common? + require + other_exists: other /= Void + do + Result := meets (other) or is_met_by (other) or else + includes (other) or is_included_by (other) or else + overlaps (other) or is_overlapped_by (other) + ensure + Result implies meets (other) or is_met_by (other) or else + includes (other) or is_included_by (other) or else + overlaps (other) or is_overlapped_by (other) + end + +feature -- Transformation + + unite (other: like Current) + -- Transform into the union between this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |------------x.union(y)----------->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + local + temp_start: like time_anchor + temp_finish: like finish + do + temp_start := start.min (other.start) + temp_finish := finish.max (other.finish) + set_start_finish (temp_start, temp_finish); + ensure + valid_result: equal (start, old start.min(other.start)) and + equal (finish, old finish.max(other.finish)) + end + + intersect (other: like Current) + -- Transform into the intersection of this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |--x.intersection(y)-->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + local + temp_start: like time_anchor + temp_finish: like finish + do + temp_start := start.max (other.start) + temp_finish := finish.min (other.finish) + set_start_finish (temp_start, temp_finish); + ensure + valid_result: equal (start, old start.max(other.start)) and + equal (finish, old finish.min(other.finish)) + end + + split (a_time: like time_anchor): like Current + -- Transform by splitting the interval at 'a_time'. + -- Result is the interval after 'a_time'. + -- | + -- time + -- | + -- V + -- |-----Current----------------->| + -- |---Current--->|----Result---->| + -- Only valid if time is within the interval. + require + time_exists: a_time /= Void + time_in_interval: a_time.belongs (Current) + do + Result := twin + set_start_finish (start, a_time) + Result.set_start_finish (a_time, Result.finish) + ensure + closure: equal (old Current, Result.union (Current)) + meets_result: Current.meets (Result) + end + +feature -- Basic operations + + union (other: like Current): like Current + -- The union between this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |------------x.union(y)----------->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + do + Result := twin + Result.unite (other) + ensure + no_side_effect: equal (Current, old Current) + valid_result: equal (Result.start, start.min(other.start)) and + equal (Result.finish, finish.max(other.finish)) + end + + intersection (other: like Current): like Current + -- The intersection of this interval and the other. + -- |-------------x------------->| + -- |-------------y------------->| + -- |--x.intersection(y)-->| + -- Only valid if at least one time point common to both. + require + other_exists: other /= Void + intersecting_intervals: intersects (other) + do + Result := twin + Result.intersect (other) + ensure + no_side_effect: equal (Current, old Current) + valid_result: equal (Result.start, start.max (other.start)) and + equal (Result.finish, finish.min(other.finish)) + end + + time_at_percent (a_ratio: DOUBLE): like time_anchor + -- Time based on some percentage of this interval. + -- Example 1: if 'a_ratio' is 0.0 then result = 'start'; if + -- 'a_ratio' is 0.5 then resulting time is 1/2 the distance + -- from start to finish; if 'a_ratio' is 2.0 then resulting time + -- is at twice the duration from start to finish. + do + Result := start + (duration * a_ratio) + end + +feature {NONE} -- Implementation + + start_imp: like time_anchor + -- Used internally to prevent changes to `start' which could otherwise + -- be induced by calls to a _TIME. + + finish_imp: like time_anchor + -- Used internally to prevent changes to `finish' which could otherwise + -- be induced by calls to a _TIME. + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: ABSTRACT_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: ABSTRACT_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +invariant + + is_initialized: start_imp /= Void and finish_imp /= Void + start_before_finish: start <= finish + positive_duration: not duration.is_negative + +end diff --git a/jj_temporal/jj_t/classes/abstract_time.e b/jj_temporal/jj_t/classes/abstract_time.e new file mode 100644 index 0000000..11899dd --- /dev/null +++ b/jj_temporal/jj_t/classes/abstract_time.e @@ -0,0 +1,273 @@ +note + description: "[ + Notion of a time, such as <1 Jan 98> or <10:30 P.M.> or , etc. + ]" + names: "abstract_time, time, date" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + ABSTRACT_TIME + +inherit + COMPARABLE + +feature -- Access + + as_string: STRING + -- The time represented as a string, ideally with not extra characters. + deferred + end + + as_integer: INTEGER + -- The time as represented by an INTEGER. + require + is_representable: is_representable_as_integer + deferred + end + +feature -- Initialization + + set_now + -- Set current time according to timezone. + deferred + end + + set_now_utc + -- Set the current object to today's date in utc format. + deferred + end + + set_now_utc_fine + -- Set the current object to today's date in utc format. + deferred + end + +feature -- Element change + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + require + valid_string_representation: is_valid_string_representation (a_string) + deferred + end + + from_integer (a_integer: INTEGER) + -- Change Current to the time represented by `a_integer'. + require + valid_integer_representation: is_valid_integer_representation (a_integer) + deferred + end + + add_duration (a_duration: like duration_anchor) + -- adds a duration to Current time + require + duration_exists: a_duration /= Void + deferred + end + +feature -- Basic operations + + plus alias "+" (a_duration: like duration_anchor): like Current + -- same as add_duration except returns a new time + require + duration_exists: a_duration /= Void + do + Result := twin + Result.add_duration (a_duration) + ensure + no_side_effect: equal (Current, old Current) + end + + minus alias "-" (a_duration: like duration_anchor): like Current + -- same as adding a negative duration except returns a new time + require + duration_exists: a_duration /= Void + do + Result := twin + Result.add_duration (a_duration.negative) + ensure + no_side_effect: equal (Current, old Current) + end + +feature -- Status report + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + deferred + end + +feature -- Querry + + is_before (a_interval: like interval_anchor): BOOLEAN + -- Is this time before the interval? + require + interval_exists: a_interval /= Void + do + Result := Current < a_interval.start + ensure + valid_result: Result implies Current < a_interval.start + end + + is_after (a_interval: like interval_anchor): BOOLEAN + -- Is this time after the interval? + require + interval_exists: a_interval /= Void + do + Result := Current > a_interval.finish + ensure + valid_result: Result implies Current > a_interval.finish + end + + belongs (a_interval: like interval_anchor): BOOLEAN + -- Does this time fall somewhere during the interval? + require + interval_exists: a_interval /= Void + do + Result := Current >= a_interval.start and Current <= a_interval.finish + ensure + valid_result: Result implies Current >= a_interval.start and Current <= a_interval.finish + end + + is_between (time_1, time_2: like Current): BOOLEAN + -- Is current between the two times? + require + others_exist: time_1 /= Void and time_2 /= Void + do + if time_1 < Current and Current < time_2 then + Result := True + elseif time_2 < Current and Current < time_1 then + Result := True + end + ensure + valid_result: Result implies ((time_1 < Current and Current < time_2) or else + (time_2 < Current and Current < time_1)) + end + + is_between_inclusive (time_1, time_2: like Current): BOOLEAN + -- Is current between the two times or equal to one of the two times? + require + others_exist: time_1 /= Void and time_2 /= Void + do + if time_1 <= Current and Current <= time_2 then + Result := True + elseif time_2 <= Current and Current <= time_1 then + Result := True + end + ensure + valid_result: Result implies ((time_1 <= Current and Current <= time_2) or else + (time_2 <= Current and Current <= time_1)) + end + + percent_of (a_interval: like interval_anchor): DOUBLE + -- Where does this time fall in relation to the interval? + -- If current time is before the interval then result should be negative. + -- If current time is after the interval then result should be > 1 (i.e. > 100%). + -- If current time belongs to the interval then result should be between 0 and 1. + require + interval_exists: a_interval /= Void + local + int: like Interval_anchor + do +-- int := twin (a_interval) + int := a_interval.deep_twin + if is_before (a_interval) then + int.set_start_finish (Current, a_interval.start) + if not a_interval.duration.is_zero then + Result := -(int.duration.percent_of (a_interval.duration)) + end + else + int.set_start_finish (a_interval.start, Current) + if not a_interval.duration.is_zero then + Result := int.duration.percent_of (a_interval.duration) + end + end + ensure + negative_if_before: Result < 0 implies Current.is_before (a_interval) + zero_to_one_if_belongs: (Result >= 0 and Result <= 1) implies Current.belongs (a_interval) + over_one_if_after: Result > 1 implies Current.is_after (a_interval) + end + + time_between (other: like Current): like duration_anchor + -- The duration of time between Current and other + require + other_exists: other /= Void + deferred + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + deferred + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in the range reconizable by Current? + deferred + end + +feature {NONE} -- Implementation + + C_date: C_DATE + -- Used to set the date and time based on system clock. + once + create Result + end + + is_valid: BOOLEAN + -- Test used by invariant. + do + Result := True + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: ABSTRACT_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: ABSTRACT_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +invariant + + always_valid: is_valid + +note + copyright: "Copyright (c) 1984-2015, 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 + + + diff --git a/jj_temporal/jj_t/classes/c_date.e b/jj_temporal/jj_t/classes/c_date.e new file mode 100644 index 0000000..e05ce51 --- /dev/null +++ b/jj_temporal/jj_t/classes/c_date.e @@ -0,0 +1,255 @@ +note + description: "Representation of a date at C level" + legal: "See notice at end of class." + status: "See notice at end of class." + date: "$Date: 2014-03-11 23:16:07 -0400 (Tue, 11 Mar 2014) $" + revision: "$Revision: 35 $" + +class + C_DATE + + -- This is a copy of C_DATE from ISE's time cluster. I copied + -- it to my support cluster so I can use it in my temporal and + -- other projects without the overhead of using all of ISE's + -- time cluster. + +inherit + ANY + redefine + default_create + end + +create + default_create, + make_utc + +feature {NONE} -- Initialization + + default_create + -- Create an instance of C_DATA using current local time. + do + is_utc := False + update + end + + make_utc + -- Create an instance of C_DATE holding UTC values. + do + is_utc := True + update + ensure + is_utc: is_utc + end + +feature -- Access + + is_utc: BOOLEAN + -- Is Current holding value in UTC format? + +feature -- Update + + update + -- Pointer to `struct tm' area. + local + l_timeb, l_tm, l_time: POINTER + l_milli: INTEGER + do + l_timeb := l_timeb.memory_alloc (timeb_structure_size) + l_time := l_time.memory_alloc (time_t_structure_size) + ftime (l_timeb) + get_time (l_timeb, l_time) + if is_utc then + l_tm := gmtime (l_time) + else + l_tm := localtime (l_time) + end + create internal_item.make_from_pointer (l_tm, tm_structure_size) + + l_milli := get_millitm (l_timeb) + if l_milli < 0 or l_milli > 999 then + millisecond_now := 0 + else + millisecond_now := l_milli + end + + l_timeb.memory_free + l_time.memory_free + end + +feature -- Status + + year_now: INTEGER + -- Current year at creation time or after last call to `update'. + do + Result := 1900 + get_tm_year (internal_item.item) + ensure + year_valid: Result >= 1900 + end + + month_now: INTEGER + -- Current month at creation time or after last call to `update'. + do + Result := get_tm_mon (internal_item.item) + 1 + ensure + month_valid: Result >= 1 and Result <= 12 + end + + day_now: INTEGER + -- Current day at creation time or after last call to `update'. + do + Result := get_tm_mday (internal_item.item) + ensure + day_valid: Result >= 1 and Result <= 31 + end + + hour_now: INTEGER + -- Current hour at creation time or after last call to `update'. + do + Result := get_tm_hour (internal_item.item) + ensure + hour_valid: Result >= 0 and Result <= 23 + end + + minute_now: INTEGER + -- Current minute at creation time or after last call to `update'. + do + Result := get_tm_min (internal_item.item) + ensure + minute_valid: Result >= 0 and Result <= 59 + end + + second_now: INTEGER + -- Current second at creation time or after last call to `update'. + do + Result := get_tm_sec (internal_item.item) + if Result > 59 then + -- Some platform returns up to 61 for leap seconds. + Result := 59 + end + ensure + second_valid: Result >= 0 and Result <= 59 + end + + millisecond_now: INTEGER + -- Current millisecond at creation time or after last call to `update'. + +feature {NONE} -- Externals + + ftime (p: POINTER) + -- Set current date and time in `p', pointer to a `struct timeb' area. + external + "C macro signature (struct timeb*) use " + end + +feature {NONE} -- `struct timeb' encapsulation + + timeb_structure_size: INTEGER + -- Size of `struct timeb'. + external + "C macro use " + alias + "sizeof(struct timeb)" + end + + time_t_structure_size: INTEGER + -- Size of `struct timeb'. + external + "C macro use " + alias + "sizeof(time_t)" + end + + tm_structure_size: INTEGER + -- Size of `struct tm'. + external + "C macro use " + alias + "sizeof(struct tm)" + end + + get_millitm (p: POINTER): INTEGER + -- Get `p->millitm'. + external + "C struct struct timeb access millitm use " + end + + get_time (p, t: POINTER) + -- Get `p->time'. + external + "C inline use , " + alias + "*(time_t *) $t = (((struct timeb *)$p)->time);" + end + +feature {NONE} -- `struct tm' encapsulation + + internal_item: MANAGED_POINTER + -- Pointer to `struct tm' area. + + localtime (t: POINTER): POINTER + -- Pointer to `struct tm' area. + external + "C inline use " + alias + "localtime ((time_t *) $t)" + end + + gmtime (t: POINTER): POINTER + -- Pointer to `struct tm' area in UTC. + external + "C inline use " + alias + "gmtime ((time_t *) $t)" + end + + get_tm_year (p: POINTER): INTEGER + -- Get `p->tm_year', number of years since 1900. + external + "C struct struct tm access tm_year use " + end + + get_tm_mon (p: POINTER): INTEGER + -- Get `p->tm_mon'. + external + "C struct struct tm access tm_mon use " + end + + get_tm_mday (p: POINTER): INTEGER + -- Get `p->tm_mday'. + external + "C struct struct tm access tm_mday use " + end + + get_tm_hour (p: POINTER): INTEGER + -- Get `p->tm_hour'. + external + "C struct struct tm access tm_hour use " + end + + get_tm_min (p: POINTER): INTEGER + -- Get `p->tm_min'. + external + "C struct struct tm access tm_min use " + end + + get_tm_sec (p: POINTER): INTEGER + -- Get `p->tm_sec'. + external + "C struct struct tm access tm_sec use " + end + +note + copyright: "Copyright (c) 1984-2006, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 356 Storke Road, 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 C_DATE diff --git a/jj_temporal/jj_t/classes/hms_constants.e b/jj_temporal/jj_t/classes/hms_constants.e new file mode 100644 index 0000000..1f46265 --- /dev/null +++ b/jj_temporal/jj_t/classes/hms_constants.e @@ -0,0 +1,34 @@ +note + description: "[ + Constants for use with HMS_TIME, HMS_DURATION, and HMS_INTERVAL. + ]" + date: "24 Aug 04" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + + +class + HMS_CONSTANTS + +feature -- Access + + One_second: HMS_DURATION + once + create Result.set (0, 0, 1) + end + + One_minute: HMS_DURATION + once + create Result.set (0, 1, 0) + end + + One_hour: HMS_DURATION + once + create Result.set (1, 0, 0) + end + +end -- class HMS_CONSTANTS diff --git a/jj_temporal/jj_t/classes/hms_duration.e b/jj_temporal/jj_t/classes/hms_duration.e new file mode 100644 index 0000000..bdf0658 --- /dev/null +++ b/jj_temporal/jj_t/classes/hms_duration.e @@ -0,0 +1,281 @@ +note + description: "[ + A duration of time represented by hours, minutes, and seconds. + ]" + names: "duration, time_duration" + date: "1999/01/01"; updated: "14 Aug 04" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_DURATION + +inherit + + ABSTRACT_DURATION + +create + default_create, + set, + set_fine + +feature -- Access + + as_string: STRING_8 + -- The time represented as a string. + do + Result := hours.out + ":" + minutes.out + ":" + seconds.out + "." + milliseconds.out + end + + hours: INTEGER + -- The number of hours in this DURATION + + minutes: INTEGER + -- The number of minutes in this DURATION + + seconds: INTEGER + -- The number of seconds in this DURATION + + milliseconds: INTEGER + -- The number of milli-seconds in this DURATION + + as_hours: DOUBLE + -- Length of this duration in hours. + do + Result := hours + minutes / 60 + seconds / 3600 + milliseconds / 3600000 + end + + as_minutes: DOUBLE + -- Length of this duration in minutes. + do + Result := hours * 60 + minutes + seconds / 60 + milliseconds / 60000 + end + + as_seconds: DOUBLE + -- Length of this duration in seconds. + do + Result := hours * 3600 + minutes * 60 + seconds + milliseconds / 1000 + end + + as_milliseconds: DOUBLE + -- Length of this duration in milliseconds + do + Result := hours * 3600000 + minutes * 60000 + seconds * 1000 + milliseconds + end + + one: like Current + -- Neutral element for '*' and '/'. + do + create Result.set_fine (1, 1, 1, 1) + ensure then + result_hours_is_one: Result.hours = 1 + result_minutes_is_one: Result.minutes = 1 + result_seconds_is_one: Result.seconds = 1 + result_millisecons_is_one: Result.milliseconds = 1 + end + + zero: like Current + -- Neutral element for '+' and '-'. + do + create Result + ensure then + result_hours_is_zero: Result.hours = 0 + result_minutes_is_zero: Result.minutes = 0 + result_seconds_is_zero: Result.seconds = 0 + result_milliseconds_is_zero: Result.milliseconds = 0 + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + do + -- Used minutes because it seemed reasonable accuracy. + Result := as_minutes / other.as_minutes + end + +feature -- Element change + + set_zero + -- Make current have zero length. + do + set_fine (0, 0, 0, 0) + end + + set (a_hours, a_minutes, a_seconds: INTEGER) + -- Change the hours, minutes, and seconds to these values + -- and set milliseconds to zero. + do + set_fine (a_hours, a_minutes, a_seconds, 0) + ensure + hours_set: hours = a_hours + minutes_set: minutes = a_minutes + seconds_set: seconds = a_seconds + milliseconds_zero: milliseconds = 0 + end + + set_fine (a_hours, a_minutes, a_seconds, a_milliseconds: INTEGER) + -- Change `hours', `minutes', `seconds', and `milliseconds' + do + hours := a_hours + minutes := a_minutes + seconds := a_seconds + milliseconds := a_milliseconds + ensure + hours_set: hours = a_hours + minutes_set: minutes = a_minutes + seconds_set: seconds = a_seconds + milliseconds_set: milliseconds = a_milliseconds + end + + set_hours (a_hours: INTEGER) + -- Change hours + do + hours := a_hours + ensure + hours_set: hours = a_hours + end + + set_minutes (a_minutes: INTEGER) + -- change minutes + do + minutes := a_minutes + ensure + minutes_set: minutes = a_minutes + end + + set_seconds (a_seconds: INTEGER) + -- Change seconds + do + seconds := a_seconds + ensure + seconds_set: seconds = a_seconds + end + + negate + -- Reverses the sign for hours, minutes, and seconds. + do + hours := -hours + minutes := -minutes + seconds := -seconds + milliseconds := -milliseconds + ensure then + hours_negated: -hours = old hours + minutes_negated: -minutes = old minutes + seconds_negated: -seconds = old seconds + milliseconds_negated: milliseconds = -milliseconds + end + + normalize + -- Convert to standard format: "61 minutes" becomes "1 hour, 1 minute". + do +-- Fix me !!! for negatives... + seconds := seconds + milliseconds // 999 + milliseconds := milliseconds \\ 999 + minutes := minutes + seconds // 60 + seconds := seconds \\ 60 + hours := hours + minutes // 60 + minutes := minutes \\ 60 + end + + add (other: like Current) + -- Add 'other'. Does not 'normalize'. + do + hours := hours + other.hours + minutes := minutes + other.minutes + seconds := seconds + other.seconds + milliseconds := milliseconds + other.milliseconds + ensure then + hours_added: hours = old hours + other.hours + minutes_added: minutes = old minutes + other.minutes + seconds_added: seconds = old seconds + other.seconds + milliseconds_added: milliseconds = old milliseconds + other.milliseconds + end + + sub (other: like Current) + -- Subtract 'other'. Does not 'normalize'. + do + hours := hours - other.hours + minutes := minutes - other.minutes + seconds := seconds - other.seconds + milliseconds := milliseconds - other.milliseconds + ensure then + hours_subbed: hours = old hours - other.hours + minutes_subbed: minutes = old minutes - other.minutes + seconds_subbed: seconds = old seconds - other.seconds + milliseconds_subbed: milliseconds = old milliseconds - other.milliseconds + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + -- Result is normalized. + local + v: DOUBLE + fract: DOUBLE + do + -- Multiply `hours' + v := hours * r + hours := v.floor + fract := v - hours + -- Multiply `minutes' and add fractional of hour + v := minutes * r + 60 * fract + minutes := v.floor + fract := v - minutes + -- Mulitply `seconds' and add fractional minute + v := seconds * r + 60 * fract + seconds := v.floor + fract := v - seconds + -- Multiply `milliseconds' and add fractional second + v := milliseconds * r + 1000 * fract + milliseconds := v.rounded + -- Normalize + normalize + end + + divide (r: DOUBLE) + -- Divide by 'r'. + -- Result is normalized. + do + set_fine (0, 0, 0, (as_milliseconds / r).rounded) + normalize + end + + div (i: INTEGER) + -- Integer division. + -- Result is normalized. + do + set (0, 0, as_seconds.truncated_to_integer // i) + normalize + end + + mod (i: INTEGER) + -- Modulo. + -- Result is normalized. + do + set (0, 0, as_seconds.truncated_to_integer \\ i) + normalize + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Is 'Current' less than 'other'? + local + temp, temp_other: like Current + do + temp := twin + temp_other := other.twin + temp.normalize + temp_other.normalize + Result := (temp.hours < temp_other.hours) or + (temp.hours = temp_other.hours and temp.minutes < temp_other.minutes) or + (temp.hours = temp_other.hours and temp.minutes = temp_other.minutes and temp.seconds < temp_other.seconds) + end + +end + + + diff --git a/jj_temporal/jj_t/classes/hms_interval.e b/jj_temporal/jj_t/classes/hms_interval.e new file mode 100644 index 0000000..c7ca4e4 --- /dev/null +++ b/jj_temporal/jj_t/classes/hms_interval.e @@ -0,0 +1,68 @@ +note + description: "[ + A span of time consisting of a start-time, finish-time + and duration described in terms of hours, minutes, and + seconds. Positive durations only. + ]" + names: "hms_interval, interval, time_span, time_interval, span" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_INTERVAL + +inherit + + ABSTRACT_INTERVAL + redefine + time_anchor, + duration_anchor + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Create an instance starting and ending at the default creation + -- value for the type of `start' time, having zero length duration. + do + -- Can't define `default_create' in ABSTRACT_INTERVAL because there + -- `start_imp' is deffered and cannot call create on a deferred type. + create start_imp + finish_imp := start_imp.twin + ensure then + same_start_and_finish: equal (start, finish) + zero_duration: duration.is_zero + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: HMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: HMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/jj_t/classes/hms_time.e b/jj_temporal/jj_t/classes/hms_time.e new file mode 100644 index 0000000..7cde6fe --- /dev/null +++ b/jj_temporal/jj_t/classes/hms_time.e @@ -0,0 +1,551 @@ +note + description: "[ + An exact point of time as on a clock. An + Hour, Minute, Second time (ie. a time). + ]" + names: "time" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_TIME + +inherit + + ABSTRACT_TIME + rename + as_integer as as_seconds + redefine + default_create, + is_valid, + duration_anchor, + interval_anchor + end + +create + default_create, + set_now, + set_now_utc, + set_now_fine, + set_now_utc_fine, + set, + set_fine, + from_seconds, + from_string + +feature {NONE} -- Initialization + + default_create + -- Create an instance with time 00:00:00 (i.e. midnight). + do + end + +feature -- Access + + hour: INTEGER + -- Hour part of time. + + minute: INTEGER + -- Minute part of time. + + second: INTEGER + -- Second part of time. + + millisecond: INTEGER + -- Millisecond part of the time. + + overflow: INTEGER + -- Number of days after a normalize (49 hours gives 2 days overflow). + + as_string: STRING + -- The time represented as a string with no seperator characters, such + -- as ":", "-", or "/". The time 23:59:59.999 becomes "235959.999" + do + create Result.make (10) + if not (hour >= 10) then + Result.append ("0") + end + Result.append (hour.out) + if not (minute >= 10) then + Result.append ("0") + end + Result.append (minute.out) + if not (second >= 10) then + Result.append ("0") + end + Result.append (second.out) + Result.append (".") + if not (millisecond >= 100) then + Result.append ("0") + end + if not (millisecond >= 10) then + Result.append ("0") + end + Result.append (millisecond.out) + end + + as_seconds: INTEGER + -- The number of seconds from midnight to the current time. + -- `Millisecond' is rounded. + do + Result := hour * 60 * 60 + minute * 60 + second + (millisecond / 1000).rounded + end + +feature -- Element Change + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + local + h, m, s, mil: INTEGER + do + h := a_string.substring (1, 2).to_integer + m := a_string.substring (3, 4).to_integer + s := a_string.substring (5, 6).to_integer + mil := a_string.substring (8, 10).to_integer + set_fine (h, m, s, mil) + end + + from_seconds (a_seconds: INTEGER) + -- Initialize as `a_seconds' from midnight. + do + set (0, 0, 0) + add_seconds (a_seconds) + end + + set_now + -- Set current time according to timezone, setting `millisecond' to zero. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set_fine (C_date.hour_now, C_date.minute_now, C_date.second_now, 0) + end + + set_now_fine + -- Set current time according to timezone, including milli-seconds. + do + C_date.update + set_fine (C_date.hour_now, C_date.minute_now, C_date.second_now, C_date.millisecond_now) + end + + set_now_utc + -- Set the current object to today's date in utc format. + -- The `millisecond' is set to zero. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set (C_date.hour_now, C_date.minute_now, C_date.second_now) + end + + set_now_utc_fine + -- Set the current object to today's date in utc format, including `millisecond'. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set_fine (C_date.hour_now, C_date.minute_now, C_date.second_now, C_date.millisecond_now) + end + + set (h, m, s: INTEGER) + -- Change the hour, minute, and second. + -- Set `millisecond' to 0. + require + hour_valid: 0 <= h and h <= 23; + minute_valid: 0 <= m and m <= 59; + second_valid: 0 <= s and s <= 59 + do + set_fine (h, m, s, 0) + ensure + hour_assigned: hour = h + minute_assigned: minute = m + second_assigned: second = s + millisecond_assigned: millisecond = 0 + end + + set_fine (h, m, s, mil: INTEGER) + -- Change the hour, minute, and second + require + hour_valid: 0 <= h and h <= 23 + minute_valid: 0 <= m and m <= 59 + second_valid: 0 <= s and s <= 59 + millisecond_valid: 0 <= mil and mil <= 999999 + do + hour := h; + minute := m; + second := s; + millisecond := mil + ensure + hour_assigned: hour = h + minute_assigned: minute = m + second_assigned: second = s + millisecond_assigned: millisecond = mil + end + + set_hour (a_hour: INTEGER) + -- Change the `hour'. + require + hour_valid: 0 <= a_hour and a_hour <= 23; + do + hour := a_hour + ensure + hour_assigned: hour = a_hour + end + + set_minute (a_minute: INTEGER) + -- Change the `minute'. + require + minute_valid: 0 <= a_minute and a_minute <= 59; + do + minute := a_minute + ensure + minute_assigned: minute = a_minute + end + + set_second (a_second: INTEGER) + -- Change the second. + require + second_valid: 0 <= a_second and a_second <= 59 + do + second := a_second + ensure + second_assigned: second = a_second + end + + set_millisecond (a_millisecond: INTEGER) + -- Change the `millisecond' + require + valid_millisecond: 0 <= a_millisecond and a_millisecond <= 999 + do + millisecond := a_millisecond + ensure + millisecond_assigned: millisecond = a_millisecond + end + + from_integer (a_integer: INTEGER) + -- Change Current to the time represented by `a_integer'. + -- `A_compact_time' must represent a date that is not BC. + do +-- Fix me !!! + end + + clear_overflow + -- Remove the `overflow' condition by seting overflow to 0. + -- (Overflows occur when `add_duration' causes the time to be past 23:59:59.999) + do + overflow := 0 + end + + truncate_to_hours + -- Reset "to the hour" (set minutes and seconds to 0). + do + set_fine (hour, 0, 0, 0) + ensure + hour_unchanged: hour = old hour + minute_zero: minute = 0 + second_zero: second = 0 + millisecond_zero: millisecond = 0 + end + + truncate_to_minutes + -- Reset "to the minute" (i.e. set seconds to 0.) + do + set_fine (hour, minute, 0, 0) + ensure + hour_unchanged: hour = old hour + minute_unchanged: minute = old minute + second_zero: second = 0 + millisecond_zero: millisecond = 0 + end + + truncate_to_seconds + -- Set the `millisecond' to zero. + -- Use when `millisecond' portion is to be ignored. + do + set_millisecond (0) + ensure + hour_unchanged: hour = old hour + minute_unchanged: minute = old minute + second_unchaged: second = old second + millisecond_zero: millisecond = 0 + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does this time come before 'other'? + require else + other_time_not_void: other /= Void + do + Result := hour < other.hour or else + (hour = other.hour) and (minute < other.minute) or else + (hour = other.hour) and (minute = other.minute) and (second < other.second) or else + (hour = other.hour) and (minute = other.minute) and (second = other.second) and (millisecond < other.millisecond) + ensure then +-- definition: Result = (hour < other.hour) or else +-- (hour = other.hour) and (minute < other.minute) or else +-- (hour = other.hour) and (minute = other.minute) and (second < other.second) or else +-- (hour = other.hour) and (minute = other.minute) and (second = other.second) and (millisecond < other.millisecond) + end + + +feature -- Basic operations + + add_duration (a_duration: like Duration_anchor) + -- Add a length of time (in hours, minutes, and seconds) to the time. + do +-- hour := hour + a_duration.hours +-- minute := minute + a_duration.minutes +-- second := second + a_duration.seconds +-- millisecond := millisecond + a_duration.milliseconds + add_milliseconds (a_duration.milliseconds) + add_seconds (a_duration.seconds) + add_minutes (a_duration.minutes) + add_hours (a_duration.hours) + end + + add_hours (a_number: INTEGER) + -- Add `a_number' of hours to the current time + local + h: INTEGER + do + h := a_number \\ 24 + hour := hour + h + check + number_now_even: (a_number - h) \\ 24 = 0 + end + overflow := (a_number - h) // 24 + if hour < 0 then + check + positive_overflow: overflow >= 1 + end + hour := hour + 24 + overflow := overflow - 1 + end + if hour >= 24 then + hour := hour - 24 + overflow := overflow + 1 + end + end + + add_minutes (a_number: INTEGER) + -- Add `a_number' of minutes to the current time. + local + m: INTEGER + do + minute := minute + a_number + m := minute + minute := minute \\ 60 + if minute < 0 then + minute := minute + 60 + add_hours (-1) + end + add_hours (m // 60) + end + + add_seconds (a_number: INTEGER) + -- Add `a_number' of seconds to the current time. + local + s: INTEGER + do + second := second + a_number + s := second + second := second \\ 60 + if second < 0 then + second := second + 60 + add_minutes (-1) + end + add_minutes (s // 60) + end + + add_milliseconds (a_number: INTEGER) + -- Add `a_number' of milliseconds to the current time. + local + ms: INTEGER + do + millisecond := millisecond + a_number + ms := millisecond + millisecond := millisecond \\ 1000 + if millisecond < 0 then + millisecond := millisecond + 1000 + add_seconds (-1) + end + add_seconds (ms // 1000) + end + +feature -- Status report + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + -- Caveat: the `milliseconds' will be lost due to rounding in `as_seconds'. + do + Result := True + end + +feature -- Querry + + time_between (other: like Current): like Duration_anchor + -- A length of time in hours, minutes, and seconds + -- between this time and other. + local + larger, smaller: like Current + h, m, s, ms: INTEGER + do + larger := max (other) + smaller := min (other) + ms := larger.millisecond - smaller.millisecond + h := larger.hour - smaller.hour + m := larger.minute - smaller.minute + s := larger.second - smaller.second + if ms < 0 then + ms := ms + 999 + s := s - 1 + end + if s < 0 then + s := s + 60 + m := m - 1 + end + if m < 0 then + m := m + 60 + h := h - 1 + end + create Result.set_fine (h, m, s, ms) + if Current < other then + Result.negate + end + end + + seconds_between (a_other: like Current): INTEGER + -- The number of seconds between Current and `other' + require + other_exists: a_other /= Void + local + larger, smaller: like Current + h, m, s, ms: INTEGER + do + larger := max (a_other) + smaller := min (a_other) + ms := larger.millisecond - smaller.millisecond + h := larger.hour - smaller.hour + m := larger.minute - smaller.minute + s := larger.second - smaller.second + if ms < 0 then + ms := ms + 999 + s := s - 1 + end + if s < 0 then + s := s + 60 + m := m - 1 + end + if m < 0 then + m := m + 60 + h := h - 1 + end + Result := h * 60 * 60 + m * 60 + s + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + local + hs, ms, ss, mils: STRING + h, m, s, mil: INTEGER + do + if a_string /= Void and then a_string.count = 10 and then equal (a_string.substring (7, 7), ".") then + hs := a_string.substring (1, 2) + ms := a_string.substring (3, 4) + ss := a_string.substring (5, 6) + mils := a_string.substring (8, 10) + if hs.is_integer and then ms.is_integer and then ss.is_integer and then mils.is_integer then + h := hs.to_integer + m := ms.to_integer + s := ms.to_integer + mil := mils.to_integer + if (h >= 0 and h <= 23) and then + (m >= 0 and m <= 59) and then + (s >= 0 and s <= 59) and then + (mil >= 0 and mil <= 999) then + Result := True + end + end + end + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in range to be converted to a time? + do + Result := a_integer >= 0 + end + +feature {NONE} -- Implementation + +-- normalize is +-- -- convert to a normal time (1 minute, 60 seconds becomes 2 minutes 0 seconds) +-- do +-- second := second + millisecond // 999 +-- millisecond := millisecond \\ 999 +-- if millisecond < 0 then +-- millisecond := millisecond + 999 +-- second := second - 1 +-- end +-- minute := minute + second // 60 +-- second := second \\ 60 +-- if second < 0 then +-- second := second + 60 +-- minute := minute - 1 +-- end +-- hour := hour + minute // 60 +-- minute := minute \\ 60 +-- if minute < 0 then +-- minute := minute + 60 +-- hour := hour - 1 +-- end +-- overflow := hour // 24 +-- hour := hour \\ 24 +-- if hour < 0 then +-- hour := hour + 24 +-- overflow := overflow - 1 +-- end +-- end + + is_valid: BOOLEAN + -- Is time in correct format? + do + Result := (0 <= millisecond and millisecond <= 999) and + (0 <= second and second <= 59) and + (0 <= minute and minute <= 59) and + (0 <= hour and hour <= 23) + ensure then + valid_result: Result implies + (0 <= millisecond and millisecond <= 999) and + (0 <= second and second <= 59) and + (0 <= minute and minute <= 59) and + (0 <= hour and hour <= 23) + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: HMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: HMS_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/jj_t/classes/hms_timer.e b/jj_temporal/jj_t/classes/hms_timer.e new file mode 100644 index 0000000..8312b26 --- /dev/null +++ b/jj_temporal/jj_t/classes/hms_timer.e @@ -0,0 +1,74 @@ +note + description: "[ + Timer for hours, minutes, seconds, and miliseconds. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_TIMER + +inherit + + HMS_INTERVAL + undefine + duration, + out + redefine + default_create, + time_anchor, + duration_anchor + end + + TIMER + undefine + time_anchor, + duration_anchor + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Set up the timer + do + Precursor {HMS_INTERVAL} + Precursor {TIMER} + create cumulative + end + + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: HMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: HMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + +end diff --git a/jj_temporal/jj_t/classes/time_stampable.e b/jj_temporal/jj_t/classes/time_stampable.e new file mode 100644 index 0000000..859df28 --- /dev/null +++ b/jj_temporal/jj_t/classes/time_stampable.e @@ -0,0 +1,60 @@ +note + description: "[ + Objects which record their creation time. + ]" + date: "1 Sep 04" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + TIME_STAMPABLE + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Initialize `Current'. + do + create timestamp.set_now_utc_fine + end + +feature -- Access + + id: STRING + -- Unique (hopefully) object id based on the creation time of the object. + -- Concatination of Current's `generating_type' and `time_stamp'. + do + Result := generating_type.name.to_string_8 + " " + timestamp.as_string + end + + timestamp: YMDHMS_TIME + -- Time this object was created + +--feature -- Comparison + +-- infix "<" (a_other: like Current): BOOLEAN is +-- -- Is Current less than `a_other'? +-- do +-- Result := id < a_other.id +---- Result := timestamp < a_other.timestamp +-- end + +invariant + + time_stamp_exists: timestamp /= Void + +end diff --git a/jj_temporal/jj_t/classes/timer.e b/jj_temporal/jj_t/classes/timer.e new file mode 100644 index 0000000..04f61b9 --- /dev/null +++ b/jj_temporal/jj_t/classes/timer.e @@ -0,0 +1,122 @@ +note + description: "[ + Stop-watch type object. + Create the object and call `reset' to use. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +deferred class + TIMER + +inherit + + ABSTRACT_INTERVAL + redefine + duration + end + +feature {NONE} -- Initialization + + default_create + -- Initialize Current + do + create lap_times.make (10) + end + +feature -- Access + + duration: like duration_anchor + -- The time between the `start' and the `finish'; + -- or the time between the `start' and the current time if + -- the timer is running. + local + t: like time_anchor + do + if is_running then + t := finish + t.set_now_utc_fine + Result := t.time_between (start) + else + Result := Precursor + end + end + + cumulative: like duration_anchor + -- Cumulative total of all the times elapsed on the timer. + -- Recalculated at every `stop'. + + i_th_lap (a_index: INTEGER): like duration_anchor + -- The `a_index'th duration. + require + is_valid_lap_index: is_valid_lap_index (a_index) + do + Result := lap_times.i_th (a_index) + end + +feature -- Status report + + is_running: BOOLEAN + -- Is the timer running? + -- (Use `start' to begin timing and `stop' to end.) + +feature -- Basic operations + + reset + -- Reset `elapsed' to zero. + do + start_imp.set_now_utc_fine + finish_imp.copy (start) + cumulative.set_zero + lap_times.wipe_out + end + + run + -- Start the timer + require + not_running: not is_running + do + is_running := True + start_imp.set_now_utc_fine + ensure + is_running: is_running + end + + stop + -- Stop the timer + require + is_running: is_running + do + is_running := False + finish_imp.set_now_utc_fine + cumulative := cumulative + duration +-- start_imp.copy (finish) +-- mark_lap + ensure + is_stopped: not is_running + end + + mark_lap + -- Record the current `lap' time in `lap_times' but keep the timer running. + do + lap_times.extend (duration) + end + +feature -- Querry + + is_valid_lap_index (a_index: INTEGER): BOOLEAN + -- Is `a_index' a valid value into the list of `lap_times'? + do + Result := lap_times.valid_index (a_index) + end + +feature {NONE} -- Implementation + + lap_times: ARRAYED_LIST [like duration_anchor] + -- List of durations for each time `mark_lap' was called. + +end diff --git a/jj_temporal/jj_t/classes/ymd_constants.e b/jj_temporal/jj_t/classes/ymd_constants.e new file mode 100644 index 0000000..1acf83d --- /dev/null +++ b/jj_temporal/jj_t/classes/ymd_constants.e @@ -0,0 +1,48 @@ +note + description: "[ + Constants for use with YMD_TIME, YMD_DURATION, and YMD_INTERVAL. + ]" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_CONSTANTS + +feature -- Access + + One_day: YMD_DURATION + once + create Result + Result.set (0, 0, 1) + end + + One_week: YMD_DURATION + once + create Result + Result.set (0, 0, 7) + end + + One_month: YMD_DURATION + once + create Result + Result.set (0, 1, 0) + end + + One_quarter: YMD_DURATION + once + create Result + Result.set (0, 3, 0) + end + + One_year: YMD_DURATION + once + create Result + Result.set (1, 0, 0) + end + +end -- class YMD_CONSTANTS diff --git a/jj_temporal/jj_t/classes/ymd_duration.e b/jj_temporal/jj_t/classes/ymd_duration.e new file mode 100644 index 0000000..3ddc736 --- /dev/null +++ b/jj_temporal/jj_t/classes/ymd_duration.e @@ -0,0 +1,325 @@ +note + description: "[ + Duration of time described in years, months, and days. + ]" + names: "ymd_duration" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_DURATION + +inherit + + ABSTRACT_DURATION + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Create an instance with zero length. + do + days_per_month := default_days_per_month + set (0, 0, 0) + end + +feature -- Access + + as_string: STRING_8 + -- The time represented as a string. + do + Result := years.out + ":" + months.out + ":" + days.out + end + + years: INTEGER + -- Number of years part. + -- Does not consider the months or days. + + months: INTEGER + -- Number of months part. + -- Does not consider the years or days. + + days: INTEGER + -- Number of days part. + -- Does not consider the months or years. + + default_days_per_month: DOUBLE = 30.4375 + -- Default value for 'days_per_month'. + -- 365.25 days per year divided by 12 months per year. + + days_per_month: DOUBLE + -- Number of days in a month. (28?, 29?, 30?, 31?) + -- Value assumed by class to do calculations involving conversion + -- from days to months to years. + -- Default = 30.4375 days / month. + + days_per_year: DOUBLE + -- Number of days in the year. Calculated based on 'days_per_month'. + -- Value assumed by class to do calculations involving conversion + -- from days to months to years. + -- Default = 365.25 days / year. + do + Result := days_per_month * 12 + end + + as_years: DOUBLE + -- Length of duration in years. + do + Result := years + months / 12 + days / days_per_year + end + + as_months: DOUBLE + -- Length of duration in months. + do + Result := years * 12 + months + days / days_per_month + end + + as_days: DOUBLE + -- Length of duration in days. + do + Result := years * days_per_year + months * days_per_month + days + end + + one: like Current + -- Neutral element for "*" and "/" + do + create Result + Result.set (1,1,1) + ensure then + result_years_is_one: Result.years = 1 + result_months_is_one: Result.months = 1 + result_days_is_one: Result.days = 1 + end + + zero: like Current + -- Neutral element for "+" and "-" + do + create Result + ensure then + result_years_is_zero: Result.years = 0 + result_months_is_zero: Result.months = 0 + result_days_is_zero: Result.days = 0 + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + -- For example: is current duration at least twice as long as other? + do +-- Result := as_months / other.as_months -- Used months because it seemed reasonable accuracy. + Result := as_days / other.as_days -- Must use days because of accuracy problems with month length. + end + + normalized: like Current + -- A copy of Current in a normalized form. + do + Result := twin + Result.normalize + end + +feature -- Element change + + set_zero + -- Make Current have zero length. + do + set (0, 0, 0) + end + + set (ys, ms, ds: INTEGER) + -- Change the length of years, months, and days. + do + years := ys + months := ms + days := ds + ensure + years_set: years = ys + months_set: months = ms + days_set: days = ds + end + + set_years (ys: INTEGER) + -- Change years + do + years := ys + ensure + years_set: years = ys + end + + set_months (ms: INTEGER) + -- Change months + do + months := ms; + ensure + months_set: months = ms + end + + set_days (ds: INTEGER) + -- Change days + do + days := ds + ensure + days_set: days = ds + end + + set_days_per_month (i: DOUBLE) + -- Change 'days_per_month' (value used in calculations + -- involving month lenghts). + require + in_range: i >= 28 and i <= 31 + do + days_per_month := i + ensure + days_per_month_set: days_per_month = i + end + +feature -- Basic operations + + negate + -- Reverse the sign on years, months, and days. + do + years := -years; + months := -months; + days := -days + ensure then + years_negated: -years = old years + months_negated: -months = old months + days_negated: -days = old days + end + + normalize + -- Convert to standard format: "13 months" becomes "1 year, 1 month". + -- Month and year length is based on 'days_per_month'. + -- This feature is hard to define. For example, is 28 days equal to + -- one month? What about 30 days? + -- This needs to be fixed. + require + days_per_month > 0 + local + m, d: DOUBLE + dpm: DOUBLE + do + -- The check on `days_per_month' was necessary because `<' which calls + -- this feature must be getting called before the object is fully + -- initialized, so at that point `days_per_month' is zero; this check + -- prevents that "floating point exception". + if days_per_month = 0 then + dpm := Default_days_per_month + else + dpm := days_per_month + end + d := days + m := d / dpm + months := months + m.truncated_to_integer + m := m - m.truncated_to_integer + d := m * dpm + days := d.truncated_to_integer +-- if (d - days) > 0.5 then +-- days := days + 1 +-- if days > dpm then +-- months := months + 1 +-- end +-- end + years := years + months // 12 + months := months \\ 12 + end + + add (other: like Current) + -- Add other to current. + do + years := years + other.years; + months := months + other.months; + days := days + other.days + ensure then + years_added: years = old years + other.years + months_added: months = old months + other.months + days_add: days = old days + other.days + end + + sub (other: like Current) + -- Subtract other from current. + do + years := years - other.years; + months := months - other.months; + days := days - other.days + ensure then + years_subbed: years = old years - other.years + months_subbed: months = old months - other.months + days_subbed: days = old days - other.days + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + -- Result is normalized. + local + v: DOUBLE + fract: DOUBLE + do + v := years * r + years := v.floor + fract := v - years + + v := months * r + 12 * fract + months := v.floor + fract := v - months + + v := days * r + days_per_month * fract + days := v.rounded + normalize + end + + divide (r: DOUBLE) + -- Divide by 'r'. + -- Result is normalized. + do + set (0, 0, (as_days / r).rounded) + normalize + end + + + div (i: INTEGER) + -- Integer division. + -- Result is normalized. + do + set (0, 0, (as_days / i).truncated_to_integer) + normalize + end + + mod (i: INTEGER) + -- Modulo of duration with 'i'. + -- Result is normalized. + do + set (0, 0, as_days.truncated_to_integer \\ i) + normalize + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Is current shorter than other? + local + temp, temp_other: like Current + do + temp := twin + temp_other := other.twin + temp.normalize + temp_other.normalize + Result := (temp.years < temp_other.years) or else + (temp.years = temp_other.years and temp.months < temp_other.months) or else + (temp.years = temp_other.years and temp.months = temp_other.months and temp.days < temp_other.days) + end + +invariant + + days_per_month_in_range: days_per_month >= 28 and days_per_month <= 31 + + +end -- class YMD_DURATION + diff --git a/jj_temporal/jj_t/classes/ymd_interval.e b/jj_temporal/jj_t/classes/ymd_interval.e new file mode 100644 index 0000000..3667805 --- /dev/null +++ b/jj_temporal/jj_t/classes/ymd_interval.e @@ -0,0 +1,67 @@ +note + description: "[ + A span of time consisting of a start-time, finish-time and duration + described in terms of years, months, and days. Positive durations only. + ]" + names: "ymd_interval, interval, time_span, time_interval, span" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_INTERVAL + +inherit + + ABSTRACT_INTERVAL + redefine + time_anchor, + duration_anchor + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Create an instance starting and ending at the default creation + -- value for the type of `start' time, having zero length duration. + do + -- Can't define `default_create' in ABSTRACT_INTERVAL because there + -- `start_imp' is deffered and cannot call create on a deferred type. + create start_imp + finish_imp := start_imp.twin + ensure then + same_start_and_finish: equal (start, finish) + zero_duration: duration.is_zero + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMD_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMD_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/jj_t/classes/ymd_time.e b/jj_temporal/jj_t/classes/ymd_time.e new file mode 100644 index 0000000..fa1c479 --- /dev/null +++ b/jj_temporal/jj_t/classes/ymd_time.e @@ -0,0 +1,671 @@ +note + description: "[ + An exact point of time as on a gregorian callendar. + Has a `Year', `Month', and `Day' (i.e. a date). + ]" + names: "date, time" + date: "1 Jan 99" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME + +inherit + + ABSTRACT_TIME + rename + as_integer as as_days, + from_integer as from_days + redefine + default_create, + is_valid, + duration_anchor, + interval_anchor + end + +create + default_create, + set_now, + set_now_utc, + set, + from_days, + from_string + +feature {NONE} -- Initialization + + default_create + -- Create an instance based on todays date. + do + set_now + end + +feature -- Access + + year: INTEGER + -- Year part of the date. + + month: INTEGER + -- Month part of the date. + + day: INTEGER + -- Day part of the date. + do + Result := internal_day + if Result > last_day_of_month then + Result := last_day_of_month + end + end + + week_number: INTEGER + -- Week of the year containing this date. + local + d: YMD_TIME + first_d: INTEGER -- Jan 1st is on what day? + do + create d + d.set (year, 1, 1) + first_d := d.weekday + Result := (((julian + first_d - 1 - 1) // 7) + 1) + ensure + result_large_enough: Result >= 1 + result_small_enough: Result <= 54 -- 53 ? 54 if leapyear falls just right. + end + + last_day_of_month: INTEGER + -- Date of last day for current month + do + inspect + month + when 2 then + if is_leapyear then + Result := 29 + else + Result := 28 + end + when 4, 6, 9, 11 then + Result := 30 + else + Result := 31 + end + ensure + day_in_range: Result >= 28 and Result <= 31 + good_not_leap: Result = 28 implies (month = 2 and not is_leapyear) + good_in_leap: Result = 29 implies (month = 2 and is_leapyear) + good_30s: Result = 30 implies (month = 4 or month = 6 or month = 9 or month = 11) + good_31s: Result = 31 implies (month=1 or month=3 or month=5 or month=7 or month=8 or month=10 or month=12) + end + + days_remaining_this_month: INTEGER + -- Number of days from current until end of month. + -- Used in some calculations. + do + Result := last_day_of_month - day + ensure + valid_result: Result >= 0 and Result < last_day_of_month + end + + julian: INTEGER + -- Day of the year between 1 and 366 + local + n,i : INTEGER + do + from + i := 1 + until + i >= month + loop + inspect i + when 2 then + if is_leapyear then + n := n + 29 + else + n := n + 28 + end + when 4,6,9,11 then + n := n + 30 + else + n := n + 31 + end + i := i + 1 + end + result := n + day + ensure + valid_leapyear_result: is_leapyear implies (1 <= Result and Result <= 366) + valid_result: not is_leapyear implies (1 <= Result and Result <= 365) + end + + + weekday: INTEGER + -- 1 for Sunday, 2 for Monday, etc + -- Only works as far back as ~2 Mar 0001. ??? + local + x : INTEGER + do + x := internal\\7 + 1 + 1 + if x > 7 then -- it can only be 8 + x := 1 + end + result := x + ensure + valid_weekday: 1 <= Result and Result <= 7 + end + + as_string: STRING + -- The date represented as a string with no spaces. + -- 18 Jan 2005 would be "20050118". + do + create Result.make (10) + if is_bc then + Result.append ("BC") + end + if not (year.abs >= 1000) then + Result.append ("0") + end + if not (year.abs >= 100) then + Result.append ("0") + end + if not (year.abs >= 10) then + Result.append ("0") + end + Result.append (year.abs.out) + if not (month >= 10) then + Result.append ("0") + end + Result.append (month.out) + if not (day >= 10) then + Result.append ("0") + end + Result.append (day.out) + end + + as_days: INTEGER + -- The number of days from midnight (00:00:00) + -- on 1 Jan 1970 to the beginning Current's `day'. + local + t: YMD_TIME + do + create t + t.set (1970, 1, 1) + Result := days_between (t) + end + +feature -- Element Change + + from_days (a_days: INTEGER) + -- Change Current to the time represented by `a_days'. + -- `A_days' is assumed to be the number of days since 1 Jan 1970. + -- `A_days' must represent a date that is not BC + do + set (1970, 1, 1) + add_days (a_days) + end + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + local + d, m, y: INTEGER + do + y := a_string.substring (1, 4).to_integer + m := a_string.substring (5, 6).to_integer + d := a_string.substring (7, 8).to_integer + set (y, m, d) + end + + set_now + -- Set the current object to today's date. + -- This was copied from ISE's DATE class with the one minor change. + do + C_date.update + set (C_date.year_now, C_date.month_now, C_date.day_now) + end + + set_now_utc + -- Set the current object to today's date in utc format. + -- This was copied from ISE's DATE class with the one minor change. + do + C_date.update + set (C_date.year_now, C_date.month_now, C_date.day_now) + end + + set_now_utc_fine + -- Set the current object to today's date in utc format. + -- This was copied from ISE's TIME class with minor changes. + do + C_date.update + set (C_date.year_now, C_date.month_now, C_date.day_now) + end + + set (a_year, a_month, a_day: INTEGER) + -- Give date new year, month, and day. + -- If day > num days in month then day will return last day in the month. + require + realistic_year: a_year /= 0 + realistic_month: a_month >= 1 and a_month <= 12 + realistic_day: a_day >= 1 and a_day <= 31 + do + year := a_year + month := a_month + internal_day := a_day + ensure + year_assigned: year = a_year + month_assigned: month = a_month + day_assigned: day = a_day + end + + set_year (a_year: INTEGER) + -- Change the year. + require + realistic_year: a_year /= 0 + do + year := a_year + ensure + year_assigned: year = a_year + end + + set_month (a_month: INTEGER) + -- Change the month. + require + realistic_month: a_month >= 1 and a_month <= 12 + do + month := a_month + ensure + month_assigned: month = a_month + end + + set_day (a_day: INTEGER) + -- Change the day. + -- If a_day > number of days in the month then + -- 'day' will be the last day of month. + require + realistic_day: a_day >= 1 and a_day <= 31 + do + internal_day := a_day + ensure + day_assigned: day = a_day + end + + truncate_to_years + -- Set the day to first day of month 1. + -- Use when all but the `year' is to be ignored. + do + set_day (1) + set_month (1) + ensure + year_unchanged: year = old year + month_one: month = 1 + day_one: day = 1 + end + + truncate_to_months + -- Set day to first day of current month. + -- Use when the `day' portion of date is to be ignored. + do + set_day (1) + ensure + year_unchanged: year = old year + month_unchanged: month = old month + day_one: day = 1 + end + +feature -- Status report + + is_leapyear: BOOLEAN + -- Is this a leapyear? + do + if is_bc then + Result := (year + 1) \\ 4 = 0 and not ((year + 1) \\ 400 = 0) + else + Result := year \\ 4 = 0 and (not (year \\ 100 = 0) or else year \\ 400 = 0) + end + end + + is_bc: BOOLEAN + -- Does the date represent a date B.C. (ie year < 1) + do + Result := year <= -1 + ensure + definition: Result implies year <= -1 + end + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + do + Result := not is_bc and then + (Current >= Minimum_representable_date and Current <= Maximum_representable_date) + end + +feature -- Querry + + days_between (other: like Current): INTEGER + -- Days between this date and 'other'. + -- Only works back to ~2 Mar 0001. + require + other_exists : other /= Void + do + Result := (other.internal - internal).abs + ensure + definition: Result = (other.internal - internal).abs + end + + time_between (other: like Current): like Duration_anchor + -- The difference between two dates as a duration + local + larger, smaller: like Current + y, m, d: INTEGER + do + larger := max (other) + smaller := min (other) + y := larger.year - smaller.year + m := larger.month - smaller.month + d := larger.day - smaller.day + if d < 0 then + d := d + smaller.last_day_of_month + m := m - 1 + end + if m < 0 then + m := m + 12 + y := y - 1 + end + create Result + Result.set (y, m, d) + if Current < other then + Result.negate + end + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in range to be converted to a time? + -- Dependent on the `internal' representation of dates. + do + -- These values were found by trial and error. This will give a + -- date from 1 Jan 0001 to 18 Oct 1,469,902, which, I believe, is + -- far enough into the future. + Result := a_integer >= 1721426 and a_integer <= 538592032 + ensure then + definition: Result implies (a_integer >= 1721426) and then + (a_integer <= 538592032) -- dependent on `internal' + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + local + bcs: detachable STRING + ys, ms, ds: STRING + y, m, d: INTEGER + pad: INTEGER -- add 2 if is "BC" + do + if a_string /= Void and then (a_string.count = 8 or a_string.count = 10) then + if a_string.count = 10 then + pad := 2 + bcs := a_string.substring (1, 2) + end + ys := a_string.substring (1 + pad, 4 + pad) + ms := a_string.substring (5 + pad, 6 + pad) + ds := a_string.substring (7 + pad, 8 + pad) + if ys.is_integer and then ms.is_integer and then ds.is_integer then + y := ys.to_integer + m := ms.to_integer + d := ds.to_integer + if (y /= 0) and then (m >= 0 and m < 12)and then (d >= 0 and d <= 31) then + Result := True + if bcs /= Void and then not equal (bcs, "BC") then + Result := False + end + end + end + end + end + +feature -- Basic operations + + add_years (a_num: INTEGER) + -- Add 'a_num' number of years to the date. Works for negative numbers also. + local + y: INTEGER + do + y := year + year := year + a_num + if year = 0 then -- Must preserve invarient: year can not be 0. + if y < 0 then -- year was less than 0 and increased to 0. + year := 1 + else -- year was greater than 0 and decreased to 0. + year := -1 + end + end + ensure + valid_date: is_valid + end + + add_months (a_num: INTEGER) + -- Add 'a_num' number of months to the date. Works for negative numbers also. + local + m: INTEGER -- store month prior making month valid to call 'add_years'. + do + month := month + a_num + m := month + month := month \\ 12 -- preserve invarient + if month < 1 then + month := month + 12 -- preserve invarient + add_years (-1) + end + add_years (m // 12) -- add a year for every multiple of 12. + ensure + valid_date: is_valid + end + + add_days (a_num: INTEGER) + -- Add 'a_num' number of days to the date. Works for negative numbers also. + local + i: INTEGER + do + if a_num > 0 then + from i := a_num + until i <= days_remaining_this_month + loop + i := i - (days_remaining_this_month + 1) + set_day (1) + add_months (1) + end + set_day (day + i) + elseif a_num < 0 then + from + i := a_num.abs + until + i < day + loop + i := (day - i).abs + add_months (-1) + set_day (last_day_of_month) + end + set_day (day - i) + else + -- do nothing if a_num = 0 + end + ensure + valid_date: is_valid + end + + add_duration (a_duration: like Duration_anchor) + -- Add a length of time (in years, months, and days) to the date. + do + add_days (a_duration.days) + add_months (a_duration.months) + add_years (a_duration.years) + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does this date come before 'other'? + require else + other_not_void: other /= Void + do + Result := year < other.year or else + (year = other.year) and (month < other.month) or else + (year = other.year) and (month = other.month) and (day < other.day) + ensure then +-- definition: year < other.year or else +-- (year = other.year) and (month < other.month) or else +-- (year = other.year) and (month = other.month) and (day < other.day) + end + +feature {YMD_TIME} -- Implementation + + frozen internal: INTEGER + -- Internal representation of YMD_TIME + -- Used internally by some features. + -- Does not work for BC dates; only works back to 1 January 0001, + -- at which time the result is 1,721,426. + -- Will work up to a date of 18 Oct 1,469,902 (found by trial). + require + not_bc: not is_bc + local + c, ya : INTEGER; + d,m,y : INTEGER; + do + d := day; + m := month; + y := year; + if m > 2 then + m := m - 3; + else + m := m + 9; + y := y - 1; + end + c := y // 100; + ya := y - 100 * c; + result := (146097 * c) // 4 + (1461 * ya) // 4 + (153 * m + 2) // 5 + d + 1721119; + ensure + result_large_enough: Result >= 1721426 + result_small_enough: Result <= 538592032 + end + + frozen from_internal (num: INTEGER) + -- Create a YMD_TIME from an internal representation. + local + y,m,d,j : INTEGER + do + j := num; + j := j - 1721119 + y := (4 * j - 1) // 146097; j := 4 * j - 1 - 146097 * y; + d := j // 4; + j := (4 * d + 3) // 1461; d := 4 * d + 3 - 1461 * j; + d := (d + 4) // 4; + m := (5 * d - 3) // 153; d := 5 * d - 3 - 153 * m; + d := (d + 5) // 5; + y := 100 * y + j; + if m < 10 then + m := m + 3; + else + m := m - 9; + y := y + 1; + end; + internal_day := d; + month := m; + year := y; + end + +feature {NONE} -- Implementation + + internal_day: INTEGER + -- Used to save last day of month if day is greater than 28, 30, or 31. + -- Actual day is calculated from this value. + + is_valid: BOOLEAN + -- Is the date logical? + do + Result := is_valid_year and is_valid_month and is_valid_day + end + + is_valid_year: BOOLEAN + -- Is the year logical? + -- Only invalid year is year "0". + do + Result := year /= 0 + ensure + definition: year /= 0 + end + + is_valid_month: BOOLEAN + -- Is the month logical? + do + Result := 1 <= month and month <= 12 + ensure + definition: 1 <= month and month <= 12 + end + + is_valid_day: BOOLEAN + -- Is the day logical based on month and year? + do + Result := day >= 1 and then + ( (day <= 28) or else + ((month=4 or month=6 or month=9 or month=11) and then day <= 30) or else + ((month=1 or month=3 or month=5 or month=7 or month=8 or month=10 or month=12) and then day <= 31) or else + (month=2 and is_leapyear and day <= 29) ) + end + +feature {NONE} -- Implementation + + Minimum_representable_date: like Current + -- The earliest date that can be represented as an integer. + -- This value is dependent on the implementation of `internal' and + -- was found by trial and error to be 1 Jan 0001. + do + create Result + Result.set_year (1) + Result.set_month (1) + Result.set_day (1) + end + + Maximum_representable_date: like Current + -- The latest date that can be represented as an integer. + -- This value is dependent on the implementation of `internal' and + -- was found by trial and error to be 18 Oct 1,469,902. + do + create Result + Result.set_year (1_469_902) + Result.set_month (10) + Result.set_day (18) + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: YMD_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require else + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: YMD_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + require else + not_callable: False + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +invariant + + is_valid: is_valid + +end -- class YMD_TIME + + diff --git a/jj_temporal/jj_t/classes/ymd_timer.e b/jj_temporal/jj_t/classes/ymd_timer.e new file mode 100644 index 0000000..45b49aa --- /dev/null +++ b/jj_temporal/jj_t/classes/ymd_timer.e @@ -0,0 +1,73 @@ +note + description: "[ + Timer for hours, minutes, seconds, and miliseconds. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: $" + revision: "$Revision: $" + +class + YMD_TIMER + +inherit + + YMD_INTERVAL + undefine + duration + redefine + default_create, + time_anchor, + duration_anchor + end + + TIMER + undefine + time_anchor, + duration_anchor + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Set up the timer + do + Precursor {YMD_INTERVAL} + Precursor {TIMER} + create cumulative + end + + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMD_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMD_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + +end diff --git a/jj_temporal/jj_t/classes/ymdhms_duration.e b/jj_temporal/jj_t/classes/ymdhms_duration.e new file mode 100644 index 0000000..1805d6e --- /dev/null +++ b/jj_temporal/jj_t/classes/ymdhms_duration.e @@ -0,0 +1,268 @@ +note + description: "[ + Duration of time described in years, months, days, + hours, minutes, and seconds. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_DURATION + +inherit + + YMD_DURATION + rename + set as ymd_set, + as_string as as_ymd_string + redefine + default_create, + zero, one, + set_zero, + as_years, as_months, as_days, + add, sub, multiply, divide, div, mod, negate, percent_of, + is_less, + normalize + end + + HMS_DURATION + rename + set as hms_set, + as_string as as_hms_string + redefine + default_create, + zero, one, + set_zero, + as_hours, as_minutes, as_seconds, + add, sub, multiply, divide, div, mod, negate, percent_of, + is_less, + normalize + select + as_hms_string + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + Precursor {YMD_DURATION} + Precursor {HMS_DURATION} + end + +feature -- Access + + as_string: STRING_8 + -- The time represented as a string. + do + Result := as_ymd_string + ":" + as_hms_string + end + + zero: like Current + -- Neutral element for "+" and "-" + do + create Result + end + + one: like Current + -- Neutral element for "*" and "/" + do + create Result + Result.set (1,1,1,1,1,1) + end + + as_years: DOUBLE + -- Length of duration in years. + do + Result := years + months / 12 + days / days_per_year + + hours / (24 * days_per_year) + minutes / (60 * 24 * days_per_year) + + seconds / (60 * 60 * 24 * days_per_year) + end + + as_months: DOUBLE + -- Length of duration in months. + do + Result := years * 12 + months + days / days_per_month + + hours / hours_per_month + minutes / (60 * hours_per_month) + + seconds / (60 * 60 * hours_per_month) + end + + as_days: DOUBLE + -- Length of duration in days. + do + Result := years * days_per_year + months * days_per_month + days + + hours / 24 + minutes / (24 * 60) + seconds / (24 * 60 * 60) + end + + as_hours: DOUBLE + -- Length of this duration in hours. + do + Result := (years * days_per_year + months * days_per_month + days) -- number of days + * 24 + hours + minutes / 60 + seconds / 3600 + end + + as_minutes: DOUBLE + -- Length of this duration in minutes. + do + Result := ((years * days_per_year + months * days_per_month + days) -- number of days + * 24 + hours) -- number of hours + * 60 + minutes + seconds / 60 + end + + as_seconds: DOUBLE + -- Length of this duration in seconds. + do + Result := (((years * days_per_year + months * days_per_month + days) -- number of days + * 24 + hours) -- number of hours + * 60 + minutes) -- number of minutes + * 60 + seconds + end + +feature -- Element change + + set (a_year, a_month, a_day, a_hour, a_minute, a_second: INTEGER) + -- Change years, months, days, hours, minutes, seconds. + do + ymd_set (a_year, a_month, a_day) + hms_set (a_hour, a_minute, a_second) + ensure + years_set: years = a_year + months_set: months = a_month + days_set: days = a_day + hours_set: hours = a_hour + minutes_set: minutes = a_minute + seconds_set: seconds = a_second + end + + set_zero + -- Make the duration be zero length. + do + ymd_set (0, 0, 0) + set_fine (0, 0, 0, 0) + end + + + negate + -- Reverse the sign for years, ..., seconds. + do + Precursor {YMD_DURATION} + Precursor {HMS_DURATION} + end + + normalize + -- Convert to standard format: "13 months" becomes "1 year, 1 month". + -- Month and year length is based on 'days_per_month'. + do + Precursor {HMS_DURATION} + set_days (days + hours // 24) + set_hours (hours \\ 24) + Precursor {YMD_DURATION} + end + + add (other: like Current) + -- Add other to current. + do + Precursor {YMD_DURATION} (other) + Precursor {HMS_DURATION} (other) + end + + sub (other: like Current) + -- Subtract other from current. + do + Precursor {YMD_DURATION} (other) + Precursor {HMS_DURATION} (other) + end + + multiply (r: DOUBLE) + -- Multiply by a factor of 'r'. + -- Result is normalized. + local + v: DOUBLE + fract: DOUBLE + do + v := years * r + years := v.floor + fract := v - years + + v := months * r + 12 * fract + months := v.floor + fract := v - months + + v := days * r + days_per_month * fract + days := v.floor + fract := v - days + + v := hours * r + 24 * fract + hours := v.floor + fract := v - hours + + v := minutes * r + 60 * fract + minutes := v.floor + fract := v - minutes + + v := seconds * r + 60 * fract + seconds := v.rounded + normalize + end + + divide (r: DOUBLE) + -- Divide by 'r'. + -- Result is normalized. + do + Precursor {HMS_DURATION} (r) -- calculates based on seconds. + end + + div (i: INTEGER) + -- Integer division. + -- Result is normalized. + do + Precursor {HMS_DURATION} (i) -- calculates based on seconds. + end + + mod (i: INTEGER) + -- Modulo. + -- Result is normalized. + do + Precursor {HMS_DURATION} (i) -- calculates based on seconds. + end + + percent_of (other: like Current): DOUBLE + -- What percent of other in length is this one? + do + Result := as_days / other.as_days -- Days seemed reasonable accuracy. + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Is this duration shorter than other? + do + Result := Precursor {YMD_DURATION} (other) or else + (years = other.years and then months = other.months and then days = other.days and then + Precursor {HMS_DURATION} (other)) + end + +feature {NONE} -- Implementation + + hours_per_year: DOUBLE + -- Number of hours in a year. + do + Result := days_per_year * 24 + end + + hours_per_month: DOUBLE + -- Number of hours in a month. + do + Result := days_per_month * 24 + end + + + +end -- class YMDHMS_DURATION + diff --git a/jj_temporal/jj_t/classes/ymdhms_duration_constants.e b/jj_temporal/jj_t/classes/ymdhms_duration_constants.e new file mode 100644 index 0000000..7773566 --- /dev/null +++ b/jj_temporal/jj_t/classes/ymdhms_duration_constants.e @@ -0,0 +1,66 @@ +note + description: "[ + Constants for use with {YMDHMS_TIME}, {YMDHMS_DURATION}, + and {YMDHMS_INTERVAL}. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_DURATION_CONSTANTS + +feature -- Access + + One_second: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 0, 0, 0, 1) + end + + One_minute: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 0, 0, 1, 0) + end + + One_hour: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 0, 1, 0, 0) + end + + One_day: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 1, 0, 0, 0) + end + + One_week: YMDHMS_DURATION + once + create Result + Result.set (0, 0, 7, 0, 0, 0) + end + + One_month: YMDHMS_DURATION + once + create Result + Result.set (0, 1, 0, 0, 0, 0) + end + + One_quarter: YMDHMS_DURATION + once + create Result + Result.set (0, 3, 0, 0, 0, 0) + end + + One_year: YMDHMS_DURATION + once + create Result + Result.set (1, 0, 0, 0, 0, 0) + end + +end -- class YMDHMS_DURATION_CONSTANTS diff --git a/jj_temporal/jj_t/classes/ymdhms_interval.e b/jj_temporal/jj_t/classes/ymdhms_interval.e new file mode 100644 index 0000000..bb617b9 --- /dev/null +++ b/jj_temporal/jj_t/classes/ymdhms_interval.e @@ -0,0 +1,60 @@ +note + description: "[ + A span of time consisting of a start-time, finish-time + and duration described in terms of years, months, + days, hours, minutes, and seconds. Positive durations only. + ]" + names: "ymdhms_interval, interval, time_span, time_interval, span" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_INTERVAL + +inherit + + HMS_INTERVAL + undefine + default_create, + time_anchor, + duration_anchor + end + + YMD_INTERVAL + redefine + time_anchor, + duration_anchor + end + +create + default_create + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMDHMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMDHMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + do + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/jj_t/classes/ymdhms_time.e b/jj_temporal/jj_t/classes/ymdhms_time.e new file mode 100644 index 0000000..6e12d31 --- /dev/null +++ b/jj_temporal/jj_t/classes/ymdhms_time.e @@ -0,0 +1,391 @@ +note + description: "[ + An exact point of time of a particular day. A Year, Month, Day, + Hour, Minute, Second - time (ie. a date and time). + ]" + names: "date, time, date_and_time" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_TIME + +inherit + + YMD_TIME + rename + set as set_ymd_time, + as_days as as_seconds, + from_days as from_seconds + redefine + default_create, + set_now, + set_now_utc, + set_now_utc_fine, + is_less, + is_valid, + add_duration, + time_between, +-- normalize, + truncate_to_years, + truncate_to_months, + as_string, + as_seconds, + from_seconds, + from_string, + is_valid_string_representation, + is_valid_integer_representation, + is_representable_as_integer, + duration_anchor, + interval_anchor + end + + HMS_TIME + rename + set as set_hms_time + redefine + default_create, + set_now, + set_now_utc, + set_now_fine, + set_now_utc_fine, + is_less, + is_valid, + add_duration, + time_between, + seconds_between, + add_hours, +-- normalize, + truncate_to_hours, + truncate_to_minutes, + as_string, + as_seconds, + from_seconds, + from_string, + is_valid_string_representation, + is_valid_integer_representation, + is_representable_as_integer, + Duration_anchor, + Interval_anchor + select + from_seconds + end + +create + default_create, + set_now, + set_now_utc, + set_now_fine, + set_now_utc_fine, + from_seconds, + from_string + +feature {NONE} -- Initialization + + default_create + -- Create an instance with todays date at midnight. + do + Precursor {HMS_TIME} + Precursor {YMD_TIME} + end + +feature -- Access + + as_string: STRING + -- String representation of Current in a compact form. + do + Result := Precursor {YMD_TIME} + Result.append ("T") + Result.append (Precursor {HMS_TIME}) + end + + as_seconds: INTEGER + -- The number of seconds from midnight (00:00:00) + -- on 1 Jan 1970 to the Current time. + local + days: INTEGER + do + days := Precursor {YMD_TIME} + Result := days * 24 * 60 * 60 + Precursor {HMS_TIME} + end + +feature -- Element Change + + from_string (a_string: STRING) + -- Change Current to the time represented by `a_string'. + -- It must be in the format as provided by `as_string'. + local + pos: INTEGER + do + pos := a_string.index_of ('T', 1) + Precursor {YMD_TIME} (a_string.substring (1, pos - 1)) + Precursor {HMS_TIME} (a_string.substring (pos + 1, a_string.count)) + end + + from_seconds (a_seconds: INTEGER) + -- Change Current to the time represented by `a_seconds'. + -- `A_seconds' is assumed to be the number of seconds since 1 Jan 1970. + -- It must represent a date that is not BC. + do + set (1970, 1, 1, 0, 0, 0) + add_seconds (a_seconds) + end + + set_now + -- Initialize the instance from the system clock unsing the + -- current time zone. + do + Precursor {HMS_TIME} + Precursor {YMD_TIME} + end + + set_now_utc + -- Initialize the instance from the system clock unsing GMT. + do + Precursor {HMS_TIME} + Precursor {YMD_TIME} + end + + set_now_fine + -- Initialize the instance from the system clock using the current + -- time zone and including milliseconds. + do + set_now + Precursor {HMS_TIME} + end + + set_now_utc_fine + -- Initialize the instance from the system clock using the GMT and + -- including milliseconds. + do + set_now_utc + Precursor {HMS_TIME} + end + + set (a_year, a_month, a_day, a_hour, a_minute, a_second: INTEGER) + -- Change the 'year', ..., 'second'. + require + year_valid: a_year /= 0; + month_valid: 1 <= a_month and a_month <= 12; + day_valid: 1 <= a_day and a_day <= 31; + hour_valid: 0 <= a_hour and a_hour <= 23; + minute_valid: 0 <= a_minute and a_minute <= 59; + second_valid: 0 <= a_second and a_second <= 59 + do + set_ymd_time (a_year, a_month, a_day); + set_hms_time (a_hour, a_minute, a_second); + end + + truncate_to_years + -- Set to midnight on the first day of month 1. + -- Use when all but the `year' is to be ignored. + do + Precursor {YMD_TIME} + set_hms_time (0, 0, 0) + ensure then + year_unchanged: year = old year + month_one: month = 1 + day_one: day = 1 + hour_zero: hour = 0 + minute_zero: minute = 0 + second_zero: second = 0 + end + + truncate_to_months + -- Set to midnight on the first day of the current month. + -- Use when all but the `year' and `month' is to be ignored. + do + Precursor {YMD_TIME} + set_hms_time (0, 0, 0) + ensure then + year_unchanged: year = old year + month_unchaged: month = old month + day_one: day = 1 + hour_zero: hour = 0 + minute_zero: minute = 0 + second_zero: second = 0 + end + + truncate_to_days + -- Set to midnight on the current day. + -- Use when the time portion of the date is to be ignored. + do + set_hms_time (0, 0, 0) + ensure then + year_unchanged: year = old year + month_unchaged: month = old month + day_unchaged: day = old day + hour_zero: hour = 0 + minute_zero: minute = 0 + second_zero: second = 0 + end + + truncate_to_hours + -- Set the `hour', `second', and `millisecond' to zero. + -- Used when these portions of the time are to be ignored. + do + set (year, month, day, hour, 0, 0) + end + + truncate_to_minutes + do + set (year, month, day, hour, minute, 0) + end + +feature -- Basic operations + + add_duration (a_duration: like duration_anchor) + -- Add a length of time (in years, months, days, + -- hours, minutes, and seconds) to the time. + do + Precursor {HMS_TIME} (a_duration) + add_days (overflow) + clear_overflow + Precursor {YMD_TIME} (a_duration) + ensure then + no_overflowing_days: overflow = 0 + end + + add_hours (a_number: INTEGER) + -- Add `a_number' of hours to the current time + do + Precursor {HMS_TIME} (a_number) + add_days (overflow) + clear_overflow + end + +feature -- Status report + + is_representable_as_integer: BOOLEAN + -- Can Current be represented as an integer? + do + Result := Precursor {HMS_TIME} and then Precursor {YMD_TIME} + end + +feature -- Querry + + time_between (other: like Current): like duration_anchor + -- The difference between two dates as a time span or duration. + local + larger, smaller: like Current + y, mon, d, h, m, s: INTEGER + do + larger := max (other) + smaller := min (other) + y := larger.year - smaller.year + mon := larger.month - smaller.month + d := larger.day - smaller.day + h := larger.hour - smaller.hour + m := larger.minute - smaller.minute + s := larger.second - smaller.second + if s < 0 then + s := s + 60 + m := m - 1 + end + if m < 0 then + m := m + 60 + h := h - 1 + end + if h < 0 then + h := h + 24 + d := d - 1 + end + if d < 0 then + d := d + smaller.last_day_of_month + mon := mon - 1 + end + if mon < 0 then + mon := mon + 12 + y := y - 1 + end + create Result + Result.set (y, mon, d, h, m, s) + if Current < other then + Result.negate + end + end + + seconds_between (a_other: like Current): INTEGER + -- The number of seconds between Current and `a_other'. + do + Result := days_between (a_other) * 24 * 60 * 60 + Precursor {HMS_TIME} (a_other) + end + + is_valid_string_representation (a_string: STRING): BOOLEAN + -- Is `a_string' in a format that can be used to initialize Current? + local + i: INTEGER + ds, ts: STRING + do + if a_string /= Void then + i := a_string.index_of ('T', 1) + ds := a_string.substring (1, i - 1) + ts := a_string.substring (i + 1, a_string.count) + Result := Precursor {YMD_TIME} (ds) and then Precursor {HMS_TIME} (ts) + end + end + + is_valid_integer_representation (a_integer: INTEGER): BOOLEAN + -- Is `a_integer' in range to be converted to a time? + do + Result := Precursor {HMS_TIME} (a_integer) and then + Precursor {YMD_TIME} (a_integer) + end + +feature -- Comparison + + is_less alias "<" (other: like Current): BOOLEAN + -- Does this date_and_time come before 'other' + do + Result := year < other.year or else + ((year = other.year) and (month < other.month)) or else + ((year = other.year) and (month = other.month) and (day < other.day)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour < other.hour)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour = other.hour) and (minute < other.minute)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour = other.hour) and (minute = other.minute) and (second < other.second)) or else + ((year = other.year) and (month = other.month) and (day = other.day) and + (hour = other.hour) and (minute = other.minute) and (second = other.second) and + (millisecond < other.millisecond)) + + end + +feature {NONE} -- Implementation + + is_valid: BOOLEAN + -- Is the date and time logical? + do + Result := Precursor {YMD_TIME} and Precursor {HMS_TIME} + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + duration_anchor: YMDHMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + interval_anchor: YMDHMS_INTERVAL + -- Anchor for features using intervals. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + +end diff --git a/jj_temporal/jj_t/classes/ymdhms_timer.e b/jj_temporal/jj_t/classes/ymdhms_timer.e new file mode 100644 index 0000000..0198e06 --- /dev/null +++ b/jj_temporal/jj_t/classes/ymdhms_timer.e @@ -0,0 +1,77 @@ +note + description: "Summary description for {YMDHMS_TIMER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + YMDHMS_TIMER + +inherit + + YMDHMS_INTERVAL + undefine + duration + redefine + default_create, + time_anchor, + duration_anchor + end + + HMS_TIMER + undefine + duration + redefine + default_create, + time_anchor, + duration_anchor + end + + YMD_TIMER + undefine + time_anchor, + duration_anchor + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + -- Set up the timer + do + Precursor {YMDHMS_INTERVAL} + Precursor {YMD_TIMER} + create cumulative + end + + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMDHMS_TIME + -- Anchor for features using times. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + duration_anchor: YMDHMS_DURATION + -- Anchor for features using durations. + -- Not to be called; just used to anchor types. + -- Declared as a feature to avoid adding an attribute. + once + check + do_not_call: False then + -- Because give no info; simply used as anchor. + end + end + + +end diff --git a/jj_temporal/jj_t/demo/jj_temporal_demo.e b/jj_temporal/jj_t/demo/jj_temporal_demo.e new file mode 100644 index 0000000..657efc8 --- /dev/null +++ b/jj_temporal/jj_t/demo/jj_temporal_demo.e @@ -0,0 +1,88 @@ +note + description: "[ + Test objects for temporal cluster. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL: $" + date: "$Date: $" + revision: "$Revision: $" + +class + JJ_TEMPORAL_DEMO + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize `Current'. + local + i: INTEGER + do + create date + create time + create date_time + io.put_string (date.out) + io.new_line + io.new_line + io.put_string (time.out) + io.new_line + io.new_line + io.put_string (date_time.out) + + create ymd_formatter + create timer_1 + create timer_2 + timer_1.reset + timer_2.reset + + from i := 1 + until i > 10 + loop + io.put_string ("i = " + i.out + "%N") + timer_1.run + ee.sleep (100) + timer_1.stop + timer_2.run + ee.sleep (1_000_000_000) + timer_2.stop + io.put_string ("timer_1.cumulative = " + timer_1.cumulative.as_seconds.out) + io.new_line + io.put_string ("timer_2.cumulative = " + timer_2.cumulative.as_seconds.out) + io.new_line + i := i + 1 + end + io.put_string ("timer_1.cumulative = " + timer_1.cumulative.as_seconds.out) + io.put_string (" %T") + io.put_string ("timer_2.cumulative = " + timer_2.cumulative.as_seconds.out) + io.new_line + +-- io.put_string ("The formatted date = ") +-- io.put_string (ymd_formatter.to_string (date) + "%N") + end + +feature -- Access + + date: YMD_TIME + -- To test a date + + time: HMS_TIME + -- To test a time + + date_time: YMDHMS_TIME + -- To test a date and time + + ymd_formatter: YMD_TIME_FORMATTER + -- To test the gobo parsers + + timer_1, timer_2: HMS_TIMER + + ee: EXECUTION_ENVIRONMENT + once + create Result + end + +end diff --git a/jj_temporal/jj_t/demo/jj_temporal_demo.ecf b/jj_temporal/jj_t/demo/jj_temporal_demo.ecf new file mode 100644 index 0000000..6cf836d --- /dev/null +++ b/jj_temporal/jj_t/demo/jj_temporal_demo.ecf @@ -0,0 +1,23 @@ + + + + + + + + + + + + /.git$ + /.svn$ + /CVS$ + /EIFGENs$ + + + + diff --git a/jj_temporal/jj_t/docs/Forum.txt b/jj_temporal/jj_t/docs/Forum.txt new file mode 100644 index 0000000..0bf6d0b --- /dev/null +++ b/jj_temporal/jj_t/docs/Forum.txt @@ -0,0 +1,18 @@ +Eiffel Forum License, version 2 + +1. Permission is hereby granted to use, copy, modify and/or + distribute this package, provided that: + * copyright notices are retained unchanged, + * any distribution of this package, whether modified or not, + includes this license text. +2. Permission is hereby also granted to distribute binary programs + which depend on this package. If the binary program depends on a + modified version of this package, you are encouraged to publicly + release the modified version of this package. + +THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE. diff --git a/jj_temporal/jj_t/docs/main_classes.png b/jj_temporal/jj_t/docs/main_classes.png new file mode 100644 index 0000000..dd2531c Binary files /dev/null and b/jj_temporal/jj_t/docs/main_classes.png differ diff --git a/jj_temporal/jj_t/formatters/hms_duration_formatter.e b/jj_temporal/jj_t/formatters/hms_duration_formatter.e new file mode 100644 index 0000000..3c4dba5 --- /dev/null +++ b/jj_temporal/jj_t/formatters/hms_duration_formatter.e @@ -0,0 +1,192 @@ +note + description: "[ + Utility class for converting {HMS_DURATION}'s to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a duration in feature `to_hms_duration' is more + relaxed. + ]" + date: "18 Feb 03" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_DURATION_FORMATTER + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + set_separator (", ") + set_hour_minute_second + end + +feature -- Access + + separator: STRING + +feature -- Element change + + set_separator (a_string: STRING) + require + string_exists: a_string /= Void + do + separator := a_string + end + + set_hour_minute_second + -- Set format to day-month-year. + do + format := hms + end + + set_second_minute_hour + do + format := smh + end + + set_hour_minute + do + format := hm + end + + set_minute_hour + do + format := mh + end + +feature -- Access + + hour_string (a_duration: HMS_DURATION): STRING + do + create Result.make(8) + Result.append_integer (a_duration.hours) + Result.append (" hour") + if a_duration.hours /= 1 and a_duration.hours /= -1 then + Result.append ("s") + end + end + + minute_string (a_duration: HMS_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.minutes) + Result.append (" minute") + if a_duration.minutes /= 1 and a_duration.minutes /= -1 then + Result.append ("s") + end + end + + second_string (a_duration: HMS_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.seconds) + Result.append (" second") + if a_duration.seconds /= 1 and a_duration.seconds /= -1 then + Result.append ("s") + end + end + + to_string (a_duration: HMS_DURATION): STRING + -- the whole duration as a string + do + create Result.make (20) + Result.append (hour_string(a_duration)) + Result.append (separator) + Result.append (minute_string(a_duration)) + Result.append (separator) + Result.append (second_string(a_duration)) + end + + string_to_duration (a_string: STRING): HMS_DURATION + -- Parse the string based on the current formatting. + require + valid_date_string: is_valid_duration_string (a_string) + do + check + fix_me: False then + end + end + +feature -- Query + + is_valid_duration_string (a_string: STRING): BOOLEAN + require + string_exists: a_string /= Void + do + -- parse the string + Result := True +-- !!! temporary + end + + is_index_in_hour_string (a_date: HMS_DURATION; a_index: INTEGER): BOOLEAN + require + date_exists: a_date /= Void +-- index_large_enough: a_index >= 1 + local + s, ds: STRING + i: INTEGER + do + s := to_string (a_date) + ds := hour_string (a_date) + i := s.substring_index (ds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ds.count-1 + end + end + + is_index_in_minute_string (a_date: HMS_DURATION; a_index: INTEGER): BOOLEAN + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_date) + ms := minute_string (a_date) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_second_string (a_date: HMS_DURATION; a_index: INTEGER): BOOLEAN + local + s, ys: STRING + i: INTEGER + do + s := to_string (a_date) + ys := second_string (a_date) + i := s.substring_index (ys, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ys.count-1 + end + end + +feature {NONE} -- Implementation + + format: INTEGER + + hms, smh, -- hours-minutes-seconds, etc + hm, mh : INTEGER = unique -- hours-minutes only + + hms_parse (a_string: STRING) + do + end + + +end -- class HMS_DURATION_FORMATTER + + diff --git a/jj_temporal/jj_t/formatters/hms_time_formatter.e b/jj_temporal/jj_t/formatters/hms_time_formatter.e new file mode 100644 index 0000000..104d4f8 --- /dev/null +++ b/jj_temporal/jj_t/formatters/hms_time_formatter.e @@ -0,0 +1,245 @@ +note + description: "[ + Utility class for converting {HMS_TIME}'s to and from + strings based on a selected `format'. While the string given + by feature `to_string' is set based on the format, the parsing + of a string to a duration in feature `to_hms_time' is more + relaxed. + ]" + date: "18 Feb 03" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + HMS_TIME_FORMATTER + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature -- Initialization + + default_create + do + set_separator (":") + hide_seconds + set_12_hour + end + +feature -- Element change + + set_separator (a_string: STRING) + require + separator_exists: a_string /= Void + do + separator := a_string + end + + set_12_hour + do + is_12_hour := True + end + + set_24_hour + do + is_12_hour := False + end + + show_seconds + do + is_seconds_shown := True + end + + hide_seconds + do + is_seconds_shown := False + end + +feature -- Access + + separator: STRING + + hour_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + local + h: INTEGER + do + h := a_time.hour + if is_12_hour and then h >= 12 then + h := h - 12 + end + if is_12_hour and then h = 0 then + h := 12 + end + create Result.make(2) + if h < 10 then + Result.append ("0") + end + Result.append_integer (h) + end + + minute_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + do + create Result.make(2) + if a_time.minute < 10 then + Result.append ("0") + end + Result.append_integer (a_time.minute) + end + + second_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + do + create Result.make(2) + if a_time.second < 10 then + Result.append ("0") + end + Result.append_integer (a_time.second) + end + + am_pm_string (a_time: like time_anchor): STRING + require + time_exists: a_time /= Void + do + create Result.make (3) + if a_time.hour >= 12 then + Result.append (" PM") + else + Result.append (" AM") + end + end + + to_string (a_time: like time_anchor): STRING + -- the whole {HMS_TIME} as a string + require + time_exists: a_time /= Void + do + create Result.make (20) + Result.append (hour_string (a_time)) + Result.append (separator) + Result.append (minute_string (a_time)) + if is_seconds_shown then + Result.append (separator) + Result.append (second_string (a_time)) + end + if is_12_hour then + Result.append (am_pm_string (a_time)) + end + end + +feature -- Status report + + is_12_hour: BOOLEAN + + is_seconds_shown: BOOLEAN + +feature -- Query + + is_valid_time_string (a_time: STRING): BOOLEAN + require + string_exists: a_time /= Void + do + -- parse the string + end + + is_index_in_hour_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, hs: STRING + i: INTEGER + do + s := to_string (a_time) + hs := hour_string (a_time) + i := s.substring_index (hs, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + hs.count-1 + end + end + + is_index_in_minute_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_time) + ms := minute_string (a_time) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_second_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ss: STRING + i: INTEGER + do + s := to_string (a_time) + ss := hour_string (a_time) + i := s.substring_index (ss, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ss.count-1 + end + end + + is_index_in_am_pm_string (a_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + time_exists: a_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ss: STRING + i: INTEGER + do + s := to_string (a_time) + ss := am_pm_string (a_time) + i := s.substring_index (ss, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ss.count-1 + end + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: HMS_TIME + -- Not to be called; just used to anchor types. + require + not_callable: False + do + check + do_not_call: False then + -- Because gives no info; simply used as anchor. + end + end + +feature {NONE} -- Implementation + + hms_parse (a_string: STRING) + do + end + + +end + + diff --git a/jj_temporal/jj_t/formatters/ymd_duration_formatter.e b/jj_temporal/jj_t/formatters/ymd_duration_formatter.e new file mode 100644 index 0000000..3986a09 --- /dev/null +++ b/jj_temporal/jj_t/formatters/ymd_duration_formatter.e @@ -0,0 +1,192 @@ +note + description: "[ + Utility class for converting {YMD_DURATION}'s to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a duration in feature `to_ymd_duration' is more + relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_DURATION_FORMATTER + +inherit + + ANY + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + set_separator (", ") + set_year_month_day + end + +feature -- Access + + separator: STRING + +feature -- Element change + + set_separator (a_string: STRING) + require + string_exists: a_string /= Void + do + separator := a_string + end + + set_day_month_year + -- Set format to day-month-year. + do + format := dmy + end + + set_year_month_day + do + format := ymd + end + + set_day_month + do + format := dm + end + + set_month_year + do + format := my + end + +feature -- Access + + year_string (a_duration: YMD_DURATION): STRING + do + create Result.make(8) + Result.append_integer (a_duration.years) + Result.append (" year") + if a_duration.years /= 1 and a_duration.years /= -1 then + Result.append ("s") + end + end + + month_string (a_duration: YMD_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.months) + Result.append (" month") + if a_duration.months /= 1 and a_duration.months /= -1 then + Result.append ("s") + end + end + + day_string (a_duration: YMD_DURATION): STRING + do + create Result.make (8) + Result.append_integer (a_duration.days) + Result.append (" day") + if a_duration.days /= 1 and a_duration.days /= -1 then + Result.append ("s") + end + end + + to_string (a_duration: YMD_DURATION): STRING + -- the whole duration as a string + do + create Result.make (20) + Result.append (day_string(a_duration)) + Result.append (separator) + Result.append (month_string(a_duration)) + Result.append (separator) + Result.append (year_string(a_duration)) + end + + string_to_duration (a_string: STRING): YMD_DURATION + -- Parse the string based on the current formatting. + require + valid_date_string: is_valid_date_string (a_string) + do + check + fix_me: False then + end + end + +feature -- Query + + is_valid_date_string (a_string: STRING): BOOLEAN + require + string_exists: a_string /= Void + do + -- parse the string + Result := True +-- !!! temporary + end + + is_index_in_day_string (a_date: YMD_DURATION; a_index: INTEGER): BOOLEAN + require + date_exists: a_date /= Void +-- index_large_enough: a_index >= 1 + local + s, ds: STRING + i: INTEGER + do + s := to_string (a_date) + ds := day_string (a_date) + i := s.substring_index (ds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ds.count-1 + end + end + + is_index_in_month_string (a_date: YMD_DURATION; a_index: INTEGER): BOOLEAN + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_date) + ms := month_string (a_date) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_year_string (a_date: YMD_DURATION; a_index: INTEGER): BOOLEAN + local + s, ys: STRING + i: INTEGER + do + s := to_string (a_date) + ys := year_string (a_date) + i := s.substring_index (ys, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ys.count-1 + end + end + + +feature {NONE} -- Implementation + + format: INTEGER + + dmy, ymd, -- day-month-year, etc + dm, my : INTEGER = unique -- day-month or month-year only + + dmy_parse (a_string: STRING) + do + end + + +end -- class YMD_DURATION_FORMATTER + + diff --git a/jj_temporal/jj_t/formatters/ymd_time_format_constants.e b/jj_temporal/jj_t/formatters/ymd_time_format_constants.e new file mode 100644 index 0000000..7a30d69 --- /dev/null +++ b/jj_temporal/jj_t/formatters/ymd_time_format_constants.e @@ -0,0 +1,133 @@ +note + description: "[ + Constants describing how {YMD_TIME}'s (dates) should appear. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME_FORMAT_CONSTANTS + +feature -- Assess + + Day_month_year: INTEGER = 0 + -- (e.g. "31 January 2004" or "31/01/04") + + Year_month_day: INTEGER = 1 + -- (e.g. "2004 January 31" or "04/01/31") + + Month_day_year: INTEGER = 2 + -- (e.g. "January 31, 2004" or "01/31/04") + + Day_month: INTEGER = 3 + -- (e.g. "31 January" or "31/01") + + Month_year: INTEGER = 4 + -- (e.g. "January 2004" or "01/04") + + days_text: LINKED_LIST [STRING] + once + create Result.make + Result.extend ("SUN") + Result.extend ("MON") + Result.extend ("TUE") + Result.extend ("WED") + Result.extend ("THU") + Result.extend ("FRI") + Result.extend ("SAT") + Result.compare_objects + end + + months_text: LINKED_LIST [STRING] + once + create Result.make + Result.extend ("JAN") + Result.extend ("FEB") + Result.extend ("MAR") + Result.extend ("APR") + Result.extend ("MAY") + Result.extend ("JUN") + Result.extend ("JUL") + Result.extend ("AUG") + Result.extend ("SEP") + Result.extend ("OCT") + Result.extend ("NOV") + Result.extend ("DEC") + Result.compare_objects + end + + long_days_text: LINKED_LIST [STRING] + once + create Result.make + Result.extend ("SUNDAY") + Result.extend ("MONDAY") + Result.extend ("TUESDAY") + Result.extend ("WEDNESDAY") + Result.extend ("THURSDAY") + Result.extend ("FRIDAY") + Result.extend ("SATURDAY") + Result.compare_objects + end + + long_months_text: LINKED_LIST [STRING] + -- + once + create Result.make + Result.extend ("JANUARY") + Result.extend ("FEBRUARY") + Result.extend ("MARCH") + Result.extend ("APRIL") + Result.extend ("MAY") + Result.extend ("JUNE") + Result.extend ("JULY") + Result.extend ("AUGUST") + Result.extend ("SEPTEMBER") + Result.extend ("OCTOBER") + Result.extend ("NOVEMBER") + Result.extend ("DECEMBER") + Result.compare_objects + end + +feature -- Querry + + is_valid_format (a_integer: INTEGER): BOOLEAN + -- Does `a_integer' represent a valid date format? + do + Result := a_integer = Day_month_year or else + a_integer = Year_month_day or else + a_integer = Month_day_year or else + a_integer = Day_month or else + a_integer = Month_year + end + + is_month (a_string: STRING): BOOLEAN + -- Does a_string represent a month? + do + Result := months_text.has (a_string.as_upper) or else + long_months_text.has (a_string.as_upper) + end + + is_weekday (a_string: STRING): BOOLEAN + -- Does `a_string' represent a weekday? + do + Result := days_text.has (a_string.as_upper) or else + long_days_text.has (a_string.as_upper) + end + + get_month (a_month: STRING): INTEGER + -- Number of the `a_month' + require + is_month: is_month (a_month) + do + if months_text.has (a_month.as_upper) then + Result := months_text.index_of (a_month.as_upper, 1) + else + Result := long_months_text.index_of (a_month.as_upper, 1) + end + end + +end diff --git a/jj_temporal/jj_t/formatters/ymd_time_formatter.e b/jj_temporal/jj_t/formatters/ymd_time_formatter.e new file mode 100644 index 0000000..3807521 --- /dev/null +++ b/jj_temporal/jj_t/formatters/ymd_time_formatter.e @@ -0,0 +1,397 @@ +note + description: "[ + Utility class for converting {YMD_TIME}'s (i.e. dates) to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a date in feature `to_ymd_time' is more relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME_FORMATTER + +inherit + + YMD_TIME_FORMAT_CONSTANTS + redefine + default_create + end + +create + default_create + +feature -- Initialization + + default_create + -- Create an instance to parse dates in "dd mmm yy" format. + do + set_separator (" ") + end + +feature -- Access + + separator: STRING + -- The character (or string) placed between the day, month, year, etc. + + to_ymd_time (a_string: STRING): like time_anchor + -- Parse `a_string' + require + string_exists: a_string /= Void + is_string_valid: is_valid (a_string) + do + Result := parsed (a_string) + ensure + result_exists: Result /= Void + end + + to_string (a_ymd_time: like time_anchor): STRING + -- The complete string representation of `a_ymd_time'. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (20) + inspect format + when Day_month_year then + if is_weekday_included then + Result.append (weekday_string (a_ymd_time)) + Result.append (", ") + end + Result.append (day_string (a_ymd_time)) + Result.append (separator) + Result.append (month_string (a_ymd_time)) + Result.append (separator) + Result.append (year_string (a_ymd_time)) + when Year_month_day then + when Month_day_year then + when Month_year then + when Day_month then + else + check + should_not_happen: False + -- because format must be one of these + end + end + end + + year_string (a_ymd_time: like time_anchor): STRING + -- The string representation of `year' feature of `a_ymd_time'. + -- Will be shortened to two characters if `is_short_format'. + do + create Result.make(4) + Result.append_integer (a_ymd_time.year) + if is_short_format then + if a_ymd_time.year < 10 then + Result.keep_tail (1) + if is_zero_padded then + Result.prepend ("0") + end + else + Result.keep_tail (2) + end + else + if is_zero_padded then + if a_ymd_time.year < 10 then + Result.prepend ("000") + elseif a_ymd_time.year < 100 then + Result.prepend ("00") + elseif a_ymd_time.year < 1000 then + Result.prepend ("0") + end + end + end + ensure + valid_length_if_short: is_short_format implies Result.count <= 2 + end + + month_string (a_ymd_time: like time_anchor): STRING + -- The string representation of `month' feature of `a_ymd_time'. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (10) + if is_month_numeric then + if is_zero_padded and a_ymd_time.month < 10 then + Result.append ("0") + end + Result.append_integer (a_ymd_time.month) + else + if is_short_format then + Result.append (months_text.i_th (a_ymd_time.month)) + else + Result.append (long_months_text.i_th (a_ymd_time.month)) + end + end + end + + day_string (a_ymd_time: like time_anchor): STRING + -- The string representation of `day' feature of `a_ymd_time'. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (2) + if is_zero_padded and a_ymd_time.day < 10 then + Result.append ("0") + end + Result.append_integer (a_ymd_time.day) + end + + weekday_string (a_ymd_time: like time_anchor): STRING + -- The string repesentation of the `weekday' of `a_ymd_time'. + -- (i.e. "Sunday", "Monday, etc. or "Sun", "Mon", etc. + require + ymd_time_exists: a_ymd_time /= Void + do + create Result.make (15) + inspect a_ymd_time.weekday + when 1 then Result.append ("Sunday") + when 2 then Result.append ("Monday") + when 3 then Result.append ("Tuesday") + when 4 then Result.append ("Wednesday") + when 5 then Result.append ("Thursday") + when 6 then Result.append ("Friday") + when 7 then Result.append ("Saturday") + else + check + should_not_happen: False + -- because `weekday' ranges from 1 to 7. + end + end + if is_short_format then + Result.keep_head (3) + end + end + +feature -- Element change + + set_separator (a_string: STRING) + -- Set `separator' to `a_string'. + require + separator_exists: a_string /= Void + do + separator := a_string + ensure + seperator_set: separator = a_string + end + + set_format (a_format: INTEGER) + -- Change `format'. + -- The values are in YMD_TIME_FORMAT_CONSTANTS + require + valid_format: is_valid_format (a_format) + do + format := a_format + end + + set_show_weekday + -- Include the day of the week in the output string. + do + is_weekday_included := True + end + + set_hide_weekday + -- Do not include the day of the week in the output string. + do + is_weekday_included := False + end + + set_format_short + -- Abriviate the `month_string' (if shown as text) to three + -- characters and shorten the year to two digits. + do + is_short_format := True + end + + set_format_long + -- Show the `month_string' (if shown as text) to the complete + -- (unabriviated) word and show the year as four digits. + do + is_short_format := False + end + + set_month_numeric + -- Make the month appear as digits, not text. + do + is_month_numeric := True + ensure + showing_month_as_digits: is_month_numeric + end + + set_month_text + -- Make the month appear as text. + -- It may be full text or abbriviated depending on `is_format_short'. + do + is_month_numeric := False + ensure + showing_month_as_text: not is_month_numeric + end + + set_pad_zeros + -- Make sure the `day_string', `year_string', and `month_string' (when + -- `is_month_numeric') are padded with leading zeros when necessary. + -- For example, in numeric form "9 Jan 2004" may be shown as "09/01/04". + do + is_zero_padded := True + ensure + zero_padding_set: is_zero_padded + end + + set_hide_zeros + -- Do not pad numeric values with leading zeros. + do + is_zero_padded := False + ensure + not_padded: not is_zero_padded + end + +feature -- Basic operations + + save_format + -- Save the `format' for restoration later. + do + saved := format + ensure + format_saved: saved = format + end + + restore_format + -- Reset `format' to the value `saved' by a call to `save_format'. + do + format := saved + ensure + format_restored: format = saved + end + +feature -- Query + + is_valid (a_string: STRING): BOOLEAN + -- Is `a_string' convertable to a date? + require + string_exists: a_string /= Void + do + Result := parsed (a_string) /= Void + ensure + definition: Result implies parsed (a_string) /= Void + end + + is_weekday_included: BOOLEAN + -- Is the day of week (ie "Monday") in ymd_time string. + + is_short_format: BOOLEAN + -- Is the year two digits instead of four and + -- is the month abriviated? + + is_month_numeric: BOOLEAN + -- Is the `month_string' shown as digits? (As opposed to a + -- textual representation such as "January".) + + is_zero_padded: BOOLEAN + -- Are digital values to be padded with leading zero's if + -- shorter than normal? + + is_index_in_day_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + ymd_time_exists: a_ymd_time /= Void +-- index_large_enough: a_index >= 1 + local + s, ds: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + ds := day_string (a_ymd_time) + i := s.substring_index (ds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ds.count-1 + end + end + + is_index_in_month_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + require + ymd_time_exists: a_ymd_time /= Void + local + s, ms: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + ms := month_string (a_ymd_time) + i := s.substring_index (ms, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ms.count-1 + end + end + + is_index_in_year_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + local + s, ys: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + ys := year_string (a_ymd_time) + i := s.substring_index (ys, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + ys.count-1 + end + end + + is_index_in_weekday_string (a_ymd_time: like time_anchor; a_index: INTEGER): BOOLEAN + local + s, wds: STRING + i: INTEGER + do + s := to_string (a_ymd_time) + wds := weekday_string (a_ymd_time) + i := s.substring_index (wds, 1) + if i > 0 then + Result := a_index >= i and a_index <= i + wds.count-1 + end + end + +feature {NONE} -- Implementation + + parsed (a_string: STRING): like time_anchor + -- Attemp to convert `a_string' to a {YMD_TIME}, returning + -- Void if unable. + require + string_exists: a_string /= Void + string_has_length: a_string.count >= 1 + local + p: YMD_TIME_PARSER + do + create p +-- p.set_format (format) +-- p.parse_string (a_string) +-- Result := p.last_value + check + fix_me: False then + end + end + + format: INTEGER + + saved: INTEGER + -- used to save the format. + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMD_TIME + -- Not to be called; just used to anchor types. + require + not_callable: False + do + check + do_not_call: False then + -- Because gives no info; simply used as anchor. + end + end + +invariant + + valid_ymd_time_format: is_valid_format (format) + +end + + diff --git a/jj_temporal/jj_t/formatters/ymdhms_duration_formatter.e b/jj_temporal/jj_t/formatters/ymdhms_duration_formatter.e new file mode 100644 index 0000000..3a6dcb2 --- /dev/null +++ b/jj_temporal/jj_t/formatters/ymdhms_duration_formatter.e @@ -0,0 +1,68 @@ +note + description: "[ + Utility class for converting {YMDHMS_DURATION}'s to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a date in feature `to_ymdhms_duration' is more + relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_DURATION_FORMATTER + +inherit + + HMS_DURATION_FORMATTER + rename + to_string as time_string, + set_separator as set_time_separator, + separator as time_separator, + string_to_duration as hms_string_to_duration, + format as hms_format + redefine + default_create + end + + YMD_DURATION_FORMATTER + rename + to_string as date_string, + set_separator as set_date_separator, + separator as date_separator, + string_to_duration as ymd_string_to_duration, + format as ymd_format + redefine + default_create + end + +create + default_create + +feature -- Initialization + + default_create + -- + do + Precursor {HMS_DURATION_FORMATTER} + Precursor {YMD_DURATION_FORMATTER} + end + +feature -- Access + + to_string (a_duration: YMDHMS_DURATION): STRING + -- the whole duration as a string + require + duration_exists: a_duration /= Void + do + create Result.make (30) + Result.append (date_string (a_duration)) + Result.append (" ") + Result.append (time_string (a_duration)) + end + +end -- class YMDHMS_DURATION_FORMATTER diff --git a/jj_temporal/jj_t/formatters/ymdhms_time_formatter.e b/jj_temporal/jj_t/formatters/ymdhms_time_formatter.e new file mode 100644 index 0000000..1fd19aa --- /dev/null +++ b/jj_temporal/jj_t/formatters/ymdhms_time_formatter.e @@ -0,0 +1,126 @@ +note + description: "[ + Utility class for converting {YMDHMS_TIME}'s (i.e. date/times) to and from + strings based on a selected `format'. While the string given + by feature `as_string' is set based on the format, the parsing + of a string to a date in feature `to_ymd_time' is more relaxed. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMDHMS_TIME_FORMATTER + +inherit + + HMS_TIME_FORMATTER + rename + set_separator as set_time_separator, + separator as time_separator + redefine + default_create, + to_string, + time_anchor + end + + YMD_TIME_FORMATTER + rename + set_separator as set_date_separator, + separator as date_separator + redefine + default_create, + to_string, + time_anchor + end + +create + default_create + +feature {NONE} -- Initialization + + default_create + do + Precursor {HMS_TIME_FORMATTER} + Precursor {YMD_TIME_FORMATTER} + end + +feature -- Access + + to_string (a_time: like time_anchor): STRING + -- the whole date as a string + do + create Result.make (30) + if not is_date_hidden then + Result.append (Precursor {YMD_TIME_FORMATTER} (a_time)) + Result.append (" ") + end + if not is_time_hidden then + Result.append (Precursor {HMS_TIME_FORMATTER} (a_time)) + end + end + +feature -- Status report + + is_time_hidden: BOOLEAN + -- Will `to_string' not include the time? + + is_date_hidden: BOOLEAN + -- Will `to_string' not include the date? + +feature -- Status setting + + hide_time + -- Make `to_string' produce a string showing the date only; + -- the time portion will not show. + do + is_time_hidden := True + is_date_hidden := False + ensure + time_is_hidden: is_time_hidden + date_is_shown: not is_date_hidden + end + + hide_date + -- Make `a_string' produce a string showing the time only; + -- the date portionn will not show. + do + is_date_hidden := True + is_time_hidden := False + ensure + date_is_hidden: is_date_hidden + time_is_shown: not is_time_hidden + end + + show_date_and_time + -- Make `to_string' produce a string showing both the date + -- portion and the time portion. This is the default. + do + is_date_hidden := False + is_time_hidden := False + ensure + date_is_shown: not is_date_hidden + time_is_shown: not is_time_hidden + end + +feature {NONE} -- Anchors (for covariant redefinitions) + + time_anchor: YMDHMS_TIME + -- Not to be called; just used to anchor types. + require else + not_callable: False + do + check + do_not_call: False then + -- Because gives no info; simply used as anchor. + end + end + +invariant + + not_both_date_and_time_hidden: not (is_date_hidden and is_time_hidden) + +end diff --git a/jj_temporal/jj_t/jj_temporal.ecf b/jj_temporal/jj_t/jj_temporal.ecf new file mode 100644 index 0000000..5ab13c6 --- /dev/null +++ b/jj_temporal/jj_t/jj_temporal.ecf @@ -0,0 +1,25 @@ + + + + + + + + + /demo$ + /.svn$ + /.git$ + /docs$ + + + ^/parsers/gobo_files$ + + + + diff --git a/jj_temporal/jj_t/parsers/classes/ymd_time_parser.e b/jj_temporal/jj_t/parsers/classes/ymd_time_parser.e new file mode 100644 index 0000000..75c958c --- /dev/null +++ b/jj_temporal/jj_t/parsers/classes/ymd_time_parser.e @@ -0,0 +1,10 @@ +note + description: "Summary description for {YMD_TIME_PARSER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + YMD_TIME_PARSER + +end diff --git a/jj_temporal/jj_t/parsers/classes/ymd_time_parser_routines.e b/jj_temporal/jj_t/parsers/classes/ymd_time_parser_routines.e new file mode 100644 index 0000000..27cde0e --- /dev/null +++ b/jj_temporal/jj_t/parsers/classes/ymd_time_parser_routines.e @@ -0,0 +1,130 @@ +note + description: "[ + Routines used by the {YMD_TIME_PARSER}. These were put here to + ease the editting. The text of class {YMD_TIME_PARSER} is produced + by "geyacc" from a discription file, so every time a change is + made "geyacc" must be run (from a dos prompt), the files moved, etc. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class YMD_TIME_PARSER_ROUTINES + +inherit + + YMD_TIME_FORMAT_CONSTANTS + undefine + default_create + end + + YMD_TIME_SCANNER_ROUTINES + +feature -- Access + + format: INTEGER + -- How the date should appear (i.e. "dd mmm yyyy", "mm/dd/yy", etc + +feature -- Element change + + set_format (a_format: INTEGER) + -- Change `format' + require + valid_format: is_valid_format (a_format) + do + format := a_format + ensure + format_was_set: format = a_format + end + +feature {NONE} -- Implementation + + process_ambiguous_day (a_possible_day, a_month, a_year: INTEGER): detachable YMD_TIME + -- Return a date if `a_possible_day' is valid for the know values of + -- `a_month' and `a_year'; void otherwise. + require + valid_month: a_month >= 1 and a_month <= 12 + valid_year: a_year /= 0 + local + d: YMD_TIME + do + create d.set (a_year, a_month, 1) + if a_possible_day >= 1 and a_possible_day <= d.last_day_of_month then + create Result.set (a_year, a_month, a_possible_day) + end + end + + process_ambiguous_day_month (a_possible_day, a_possible_month, a_year: INTEGER): YMD_TIME + -- Only the year is known; determine which of the other two values is + -- the month and which is the day. + require + valid_year: a_year /= 0 + unknown_day_from_scanner: a_possible_day <= 12 + unknown_month_from_scanner: a_possible_month <= 12 + do + create Result.set (a_year, a_possible_month, a_possible_day) + end + + process_ambiguous_day_year (a_possible_day, a_month, a_possible_year: INTEGER): YMD_TIME + -- Only the month is know for sure. + require + valid_month: a_month >= 1 and a_month <= 12 + unknown_day_from_scanner: a_possible_day <= 12 + unknown_year_from_scanner: a_possible_year <= 12 + do + create Result.set (a_possible_day, a_month, a_possible_year) + end + + process_unspecified (a_day, a_month, a_year: INTEGER): YMD_TIME + -- One of `a_day' or `a_year' was not specified in the scanned string. + -- The unspecified one will be 0. + require + one_zero: a_day = 0 or a_year = 0 + valid_month: a_month >= 1 and a_month <= 12 + local + d: YMD_TIME + do + if a_day = 0 then + create Result.set (a_year, a_month, 1) + else + create d.set_now + create Result.set_now + Result.set_day (a_day) + Result.set_month (a_month) + if Result < d then + Result.set_year (Result.year + 1) + end + end + end + + process_three_numbers (int_1, int_2, int_3: INTEGER): YMD_TIME + -- Scanner encountered a three-integer date and was unable to determine + -- from the context what any of them mean. + require + int_1_is_number: int_1 >= 1 and int_1 <= 31 + int_2_is_number: int_2 >= 1 and int_2 <= 31 + int_3_is_number: int_3 >= 1 and int_3 <= 31 + do + + create Result.set (int_1, int_2, int_3) + end + + process_two_numbers (int_1, int_2: INTEGER): YMD_TIME + -- Scanner only found 2 numbers and unknow what they represent. + require + int_1_is_number: int_1 >= 1 and int_1 <= 31 + int_2_is_number: int_2 >= 1 and int_2 <= 31 + do + create Result.set_now + Result.set_day (int_1) + Result.set_month (int_2) + end + +invariant + + valid_ymd_time_format: is_valid_format (format) + +end -- Class YMD_TIME_PARSER_ROUTINES diff --git a/jj_temporal/jj_t/parsers/classes/ymd_time_scanner_routines.e b/jj_temporal/jj_t/parsers/classes/ymd_time_scanner_routines.e new file mode 100644 index 0000000..e117b12 --- /dev/null +++ b/jj_temporal/jj_t/parsers/classes/ymd_time_scanner_routines.e @@ -0,0 +1,69 @@ +note + description: "[ + Routines used by the {YMD_TIME_SCANNER}. These were put here to + ease the editting. The text of class {YMD_TIME_SCANNER} is produced + by "gelex" from a discription file, so every time a change is + made "geyacc" must be run (from a dos prompt), the files moved, etc. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME_SCANNER_ROUTINES + +inherit + + YMD_TIME_FORMAT_CONSTANTS + undefine + default_create + end + +feature {NONE} -- Inititalization + + default_create + + -- Create an instance + do + end + +feature -- Access + + last_string: detachable STRING + -- Last string value read to pass to parser + + last_integer: INTEGER + -- Last integer value read to pass to parser. + + last_value: detachable ANY + -- Last value read by the scanner + +feature {NONE} -- Implementation + + comas_removed (a_number_string: STRING): STRING + -- Return the string without comas. + -- Used to remove comas from reals or strings. + local + s: STRING + i, n: INTEGER + c: CHARACTER + do + create Result.make (200) + s := a_number_string + n := a_number_string.count + from i := 1 until i > n + loop + c := s.item (i) + if c /= ',' then + Result.append_character (c) + end + i := i + 1 + end + end + +invariant + +end -- class YMD_TIME_SCANNER_ROUTINES diff --git a/jj_temporal/jj_t/parsers/classes/ymd_time_tokens.e b/jj_temporal/jj_t/parsers/classes/ymd_time_tokens.e new file mode 100644 index 0000000..26294eb --- /dev/null +++ b/jj_temporal/jj_t/parsers/classes/ymd_time_tokens.e @@ -0,0 +1,49 @@ +note + + description: "Parser token codes" + generator: "geyacc version 3.4" + +class YMD_TIME_TOKENS + + +feature -- Last values + + last_any_value: detachable ANY + +feature -- Access + + token_name (a_token: INTEGER): STRING + -- Name of token `a_token' + do + inspect a_token + when 0 then + Result := "EOF token" + when -1 then + Result := "Error token" + when SCAN_ERROR_TOKEN then + Result := "SCAN_ERROR_TOKEN" + when WEEKDAY_TOKEN then + Result := "WEEKDAY_TOKEN" + when YEAR_TOKEN then + Result := "YEAR_TOKEN" + when MONTH_TOKEN then + Result := "MONTH_TOKEN" + when YEAR_OR_DAY_TOKEN then + Result := "YEAR_OR_DAY_TOKEN" + when NUMBER_TOKEN then + Result := "NUMBER_TOKEN" + else + Result := "Unknown token" + end + end + +feature -- Token codes + + SCAN_ERROR_TOKEN: INTEGER = 258 + WEEKDAY_TOKEN: INTEGER = 259 + YEAR_TOKEN: INTEGER = 260 + MONTH_TOKEN: INTEGER = 261 + YEAR_OR_DAY_TOKEN: INTEGER = 262 + NUMBER_TOKEN: INTEGER = 263 + +end diff --git a/jj_temporal/jj_t/parsers/gobo_files/gelex.exe b/jj_temporal/jj_t/parsers/gobo_files/gelex.exe new file mode 100644 index 0000000..73ef357 Binary files /dev/null and b/jj_temporal/jj_t/parsers/gobo_files/gelex.exe differ diff --git a/jj_temporal/jj_t/parsers/gobo_files/geyacc.exe b/jj_temporal/jj_t/parsers/gobo_files/geyacc.exe new file mode 100644 index 0000000..316a799 Binary files /dev/null and b/jj_temporal/jj_t/parsers/gobo_files/geyacc.exe differ diff --git a/jj_temporal/jj_t/parsers/gobo_files/old_gelex.exe b/jj_temporal/jj_t/parsers/gobo_files/old_gelex.exe new file mode 100644 index 0000000..bf7ed51 Binary files /dev/null and b/jj_temporal/jj_t/parsers/gobo_files/old_gelex.exe differ diff --git a/jj_temporal/jj_t/parsers/gobo_files/old_geyacc.exe b/jj_temporal/jj_t/parsers/gobo_files/old_geyacc.exe new file mode 100644 index 0000000..f0c70b9 Binary files /dev/null and b/jj_temporal/jj_t/parsers/gobo_files/old_geyacc.exe differ diff --git a/jj_temporal/jj_t/parsers/gobo_files/y.bat b/jj_temporal/jj_t/parsers/gobo_files/y.bat new file mode 100644 index 0000000..9e26023 --- /dev/null +++ b/jj_temporal/jj_t/parsers/gobo_files/y.bat @@ -0,0 +1,7 @@ +cd d: +cd e_source +cd parser_tests +cd date_parser +cd discription_files +geyacc -t ymd_time_tokens -o ymd_time_parser.e ymd_time_parser.y +gelex -o ymd_time_scanner.e ymd_time_scanner.l diff --git a/jj_temporal/jj_t/parsers/gobo_files/ymd_time_parser.y b/jj_temporal/jj_t/parsers/gobo_files/ymd_time_parser.y new file mode 100644 index 0000000..2b06bf9 --- /dev/null +++ b/jj_temporal/jj_t/parsers/gobo_files/ymd_time_parser.y @@ -0,0 +1,191 @@ +%{ +indexing + description: "[ + Parser for reading in a string and converting it to a date. + This file was produced by 'geyacc' (from the gobo tools cluster) + using file 'ymd_time_parser.y'. + ]" + date: "17 Aug 04" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class YMD_TIME_PARSER + +inherit + + YY_PARSER_SKELETON + rename + make as make_parser_skeleton + redefine + default_create + end + + YMD_TIME_PARSER_ROUTINES + rename + last_value as last_scanner_value + redefine + default_create + end + + YMD_TIME_SCANNER + rename + last_value as last_scanner_value + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create is + -- Create a new Eiffel parser. + do + Precursor {YMD_TIME_SCANNER} + make_parser_skeleton + end + +feature -- Access + + last_value: YMD_TIME + -- The result of parsing + +feature -- Basic operations + + parse_string (a_string: STRING) is + -- Parse `a_string'. + local + b: KL_CHARACTER_BUFFER + yy_buf: YY_BUFFER + f: FILE + s: STRING + do + reset + -- The `b' must end in "%U%U". I don't know why. + -- so append it onto the end of a copy of `a_string'. + s := deep_clone (a_string) + s.append ("%U%U") + create b.make_from_string (s) + create yy_buf.make_from_buffer (b) + set_input_buffer (yy_buf) + parse + end + +------------------------------------------------------------------------------------- +-------------------- Following created by GeYacc ---------------------------------- + + +%} + +%token SCAN_ERROR_TOKEN + +%token WEEKDAY_TOKEN +%token YEAR_TOKEN +%token MONTH_TOKEN +%token YEAR_OR_DAY_TOKEN +%token NUMBER_TOKEN + +%type Date +%type Ambiguous_day +%type Ambiguous_day_month +%type Unspecified +%type Weekday_included +%type Three_numbers +%type Two_numbers + +%type Month +%type Year +%type Year_or_day +%type Number + +-------------------------------------------------------------------------------- +%% + +Date: -- Empty { parsed_result := "No date entered" } + | Ambiguous_day { $$ := $1 last_value := $$ } + | Ambiguous_day_month { $$ := $1 last_value := $$ } + | Unspecified { $$ := $1 last_value := $$ } + | Three_numbers { $$ := $1 last_value := $$ } + | Two_numbers { $$ := $1 last_value := $$ } + | Weekday_included { $$ := $1 last_value := $$ } +-- | SCAN_ERROR_TOKEN { $$ := last_scanner_value last_value := $$ } + ; + +-- The Month and Year are known. +Ambiguous_day: Number Month Year { $$ := process_ambiguous_day ($1, $2, $3) } + | Year_or_day Month Year { $$ := process_ambiguous_day ($1, $2, $3) } + | Month Year_or_day Year { $$ := process_ambiguous_day ($2, $1, $3) } + | Month Number Year { $$ := process_ambiguous_day ($2, $1, $3) } + ; + +-- Only the Year is certain. +Ambiguous_day_month: Year_or_day Number Year { $$ := process_ambiguous_day ($1, $2, $3) } + | Number Year_or_day Year { $$ := process_ambiguous_day ($2, $1, $3) } + | Year Year_or_day Number { $$ := process_ambiguous_day ($2, $3, $1) } + | Year Number Year_or_day { $$ := process_ambiguous_day ($3, $2, $1) } + | Number Number Year { $$ := process_ambiguous_day_month ($1, $2, $3) } + | Year Number Number { $$ := process_ambiguous_day_month ($2, $3, $1) } + ; + +-- Two values input and at least one can be identified; assumptions are made about the unknowns. +Unspecified: Month Year { $$ := process_unspecified (0, $1, $2) } + | Year Month { $$ := process_unspecified (0, $2, $1) } + | Year_or_day Month { $$ := process_unspecified ($1, $2, 0) } + | Month Year_or_day { $$ := process_unspecified ($2, $1, 0) } + | Number Year { $$ := process_unspecified (0, $1, $2) } + | Year Number { $$ := process_unspecified (0, $2, $1) } + | Number Month { $$ := process_unspecified ($1, $2, 0) } + | Month Number { $$ := process_unspecified ($2, $1, 0) } + ; + +-- A date with the weekday included; the weekday is ignored. +Weekday_included: Weekday Ambiguous_day { $$ := $2 } + | Weekday Ambiguous_day_month { $$ := $2 } + | Weekday Unspecified { $$ := $2 } + | Weekday Three_numbers { $$ := $2 } + | Weekday Two_numbers { $$ := $2 } + ; + +-- The date is entered as three numbers and scanner is unable to deduce from +-- the values which one is day, year, and so on. +Three_numbers: Number Number Number { $$ := process_three_numbers ($1, $2, $3) } + | Year_or_day Number Number { $$ := process_three_numbers ($1, $2, $3) } + | Number Year_or_day Number { $$ := process_three_numbers ($1, $2, $3) } + | Number Number Year_or_day { $$ := process_three_numbers ($1, $2, $3) } + ; + +-- The date was enterred as only two numbers and the scanner was unable +-- to deduce thier meanings. +Two_numbers: Number Number { $$ := process_two_numbers ($1, $2) } + | Year_or_day Number { $$ := process_two_numbers ($1, $2) } + | Number Year_or_day { $$ := process_two_numbers ($1, $2) } + ; + + +-------------------------------------------------------------------------------- + +Weekday: WEEKDAY_TOKEN { -- do nothing as result is not needed + } + ; + +Month: MONTH_TOKEN { $$ := last_integer } + ; + +Year: YEAR_TOKEN { $$ := last_integer } + ; + +Year_or_day: YEAR_OR_DAY_TOKEN { $$ := last_integer } + ; + +Number: NUMBER_TOKEN { $$ := last_integer } + ; + + +%% + +end -- class YMD_TIME_PARSER diff --git a/jj_temporal/jj_t/parsers/gobo_files/ymd_time_scanner.l b/jj_temporal/jj_t/parsers/gobo_files/ymd_time_scanner.l new file mode 100644 index 0000000..293ebc2 --- /dev/null +++ b/jj_temporal/jj_t/parsers/gobo_files/ymd_time_scanner.l @@ -0,0 +1,149 @@ +%{ +indexing + description: "[ + Scanner for reading in a string and converting it to a date. + This file was produced by 'gelex' (from the gobo tools cluster) + using file "ymd_time_scanner.l". + ]" + date: "17 Aug 04" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class YMD_TIME_SCANNER + +inherit + + YY_COMPRESSED_SCANNER_SKELETON + export + {NONE} all + {ANY} scanning_error + redefine + default_create + end + + UT_CHARACTER_CODES + export + {NONE} all + redefine + default_create + end + + YMD_TIME_TOKENS + export + {NONE} all + redefine + default_create + end + + YMD_TIME_SCANNER_ROUTINES + export + {NONE} all + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create is + -- Create a scanner object + do + make + Precursor {YMD_TIME_SCANNER_ROUTINES} + end + +feature -- Basic operations + + scan_string (a_string: STRING) is + -- Scan `a_string' + local + b: KL_CHARACTER_BUFFER + yy_buf: YY_BUFFER + f: FILE + s: STRING + do + -- The `b' must end in "%U%U". I don't know why. + -- so append it onto the end of a copy of `a_string'. + s := deep_clone (a_string) + s.append ("%U%U") + create b.make_from_string (s) + create yy_buf.make_from_buffer (b) + set_input_buffer (yy_buf) + scan + end + + print_values is + do + io.put_string ("token = ") + io.put_string (token_name (last_token)) + io.put_string (" value = ") + if last_value /= Void then + io.put_string (last_value.out) + else + io.put_string ("Void") + end + io.new_line + end + +--------------------------------------------------------------------------------- +----------------------- Following code produce by Gelex ---------------------- + +%} + +--%x IN_STR -- line 50 +%option outfile="ymd_time_scanner.e" + + +IDENTIFIER [a-zA-Z][a-zA-Z]* + +DIGIT [0-9] +INTEGER {DIGIT}+|{DIGIT}{1,3}(,{DIGIT}{3})+ + +SEPARATORS [:./\\,\- \t\n\r]+ + +%% + +{INTEGER} { + last_integer := comas_removed (text).to_integer + last_value := last_integer + if last_integer > 31 then + last_token := YEAR_TOKEN + elseif last_integer > 12 then + last_token := YEAR_OR_DAY_TOKEN + else + last_token := NUMBER_TOKEN + end + print_values + } + +{IDENTIFIER} { if is_month (text) then + last_token := MONTH_TOKEN + last_integer := get_month (text) + last_value := last_integer + elseif is_weekday (text) then + last_token := WEEKDAY_TOKEN + last_string := text + last_value := text + else + last_token := SCAN_ERROR_TOKEN + last_value := last_string + print_values + end + print_values + } + +{SEPARATORS} { last_value := text + print_values + } + + +%% + + +end -- class YMD_TIME_SCANNER \ No newline at end of file diff --git a/jj_temporal/jj_temporal.ecf b/jj_temporal/jj_temporal.ecf new file mode 100644 index 0000000..5ab13c6 --- /dev/null +++ b/jj_temporal/jj_temporal.ecf @@ -0,0 +1,25 @@ + + + + + + + + + /demo$ + /.svn$ + /.git$ + /docs$ + + + ^/parsers/gobo_files$ + + + + diff --git a/jj_temporal/parsers/classes/ymd_time_parser.e b/jj_temporal/parsers/classes/ymd_time_parser.e new file mode 100644 index 0000000..75c958c --- /dev/null +++ b/jj_temporal/parsers/classes/ymd_time_parser.e @@ -0,0 +1,10 @@ +note + description: "Summary description for {YMD_TIME_PARSER}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + YMD_TIME_PARSER + +end diff --git a/jj_temporal/parsers/classes/ymd_time_parser_routines.e b/jj_temporal/parsers/classes/ymd_time_parser_routines.e new file mode 100644 index 0000000..27cde0e --- /dev/null +++ b/jj_temporal/parsers/classes/ymd_time_parser_routines.e @@ -0,0 +1,130 @@ +note + description: "[ + Routines used by the {YMD_TIME_PARSER}. These were put here to + ease the editting. The text of class {YMD_TIME_PARSER} is produced + by "geyacc" from a discription file, so every time a change is + made "geyacc" must be run (from a dos prompt), the files moved, etc. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class YMD_TIME_PARSER_ROUTINES + +inherit + + YMD_TIME_FORMAT_CONSTANTS + undefine + default_create + end + + YMD_TIME_SCANNER_ROUTINES + +feature -- Access + + format: INTEGER + -- How the date should appear (i.e. "dd mmm yyyy", "mm/dd/yy", etc + +feature -- Element change + + set_format (a_format: INTEGER) + -- Change `format' + require + valid_format: is_valid_format (a_format) + do + format := a_format + ensure + format_was_set: format = a_format + end + +feature {NONE} -- Implementation + + process_ambiguous_day (a_possible_day, a_month, a_year: INTEGER): detachable YMD_TIME + -- Return a date if `a_possible_day' is valid for the know values of + -- `a_month' and `a_year'; void otherwise. + require + valid_month: a_month >= 1 and a_month <= 12 + valid_year: a_year /= 0 + local + d: YMD_TIME + do + create d.set (a_year, a_month, 1) + if a_possible_day >= 1 and a_possible_day <= d.last_day_of_month then + create Result.set (a_year, a_month, a_possible_day) + end + end + + process_ambiguous_day_month (a_possible_day, a_possible_month, a_year: INTEGER): YMD_TIME + -- Only the year is known; determine which of the other two values is + -- the month and which is the day. + require + valid_year: a_year /= 0 + unknown_day_from_scanner: a_possible_day <= 12 + unknown_month_from_scanner: a_possible_month <= 12 + do + create Result.set (a_year, a_possible_month, a_possible_day) + end + + process_ambiguous_day_year (a_possible_day, a_month, a_possible_year: INTEGER): YMD_TIME + -- Only the month is know for sure. + require + valid_month: a_month >= 1 and a_month <= 12 + unknown_day_from_scanner: a_possible_day <= 12 + unknown_year_from_scanner: a_possible_year <= 12 + do + create Result.set (a_possible_day, a_month, a_possible_year) + end + + process_unspecified (a_day, a_month, a_year: INTEGER): YMD_TIME + -- One of `a_day' or `a_year' was not specified in the scanned string. + -- The unspecified one will be 0. + require + one_zero: a_day = 0 or a_year = 0 + valid_month: a_month >= 1 and a_month <= 12 + local + d: YMD_TIME + do + if a_day = 0 then + create Result.set (a_year, a_month, 1) + else + create d.set_now + create Result.set_now + Result.set_day (a_day) + Result.set_month (a_month) + if Result < d then + Result.set_year (Result.year + 1) + end + end + end + + process_three_numbers (int_1, int_2, int_3: INTEGER): YMD_TIME + -- Scanner encountered a three-integer date and was unable to determine + -- from the context what any of them mean. + require + int_1_is_number: int_1 >= 1 and int_1 <= 31 + int_2_is_number: int_2 >= 1 and int_2 <= 31 + int_3_is_number: int_3 >= 1 and int_3 <= 31 + do + + create Result.set (int_1, int_2, int_3) + end + + process_two_numbers (int_1, int_2: INTEGER): YMD_TIME + -- Scanner only found 2 numbers and unknow what they represent. + require + int_1_is_number: int_1 >= 1 and int_1 <= 31 + int_2_is_number: int_2 >= 1 and int_2 <= 31 + do + create Result.set_now + Result.set_day (int_1) + Result.set_month (int_2) + end + +invariant + + valid_ymd_time_format: is_valid_format (format) + +end -- Class YMD_TIME_PARSER_ROUTINES diff --git a/jj_temporal/parsers/classes/ymd_time_scanner_routines.e b/jj_temporal/parsers/classes/ymd_time_scanner_routines.e new file mode 100644 index 0000000..e117b12 --- /dev/null +++ b/jj_temporal/parsers/classes/ymd_time_scanner_routines.e @@ -0,0 +1,69 @@ +note + description: "[ + Routines used by the {YMD_TIME_SCANNER}. These were put here to + ease the editting. The text of class {YMD_TIME_SCANNER} is produced + by "gelex" from a discription file, so every time a change is + made "geyacc" must be run (from a dos prompt), the files moved, etc. + ]" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class + YMD_TIME_SCANNER_ROUTINES + +inherit + + YMD_TIME_FORMAT_CONSTANTS + undefine + default_create + end + +feature {NONE} -- Inititalization + + default_create + + -- Create an instance + do + end + +feature -- Access + + last_string: detachable STRING + -- Last string value read to pass to parser + + last_integer: INTEGER + -- Last integer value read to pass to parser. + + last_value: detachable ANY + -- Last value read by the scanner + +feature {NONE} -- Implementation + + comas_removed (a_number_string: STRING): STRING + -- Return the string without comas. + -- Used to remove comas from reals or strings. + local + s: STRING + i, n: INTEGER + c: CHARACTER + do + create Result.make (200) + s := a_number_string + n := a_number_string.count + from i := 1 until i > n + loop + c := s.item (i) + if c /= ',' then + Result.append_character (c) + end + i := i + 1 + end + end + +invariant + +end -- class YMD_TIME_SCANNER_ROUTINES diff --git a/jj_temporal/parsers/classes/ymd_time_tokens.e b/jj_temporal/parsers/classes/ymd_time_tokens.e new file mode 100644 index 0000000..26294eb --- /dev/null +++ b/jj_temporal/parsers/classes/ymd_time_tokens.e @@ -0,0 +1,49 @@ +note + + description: "Parser token codes" + generator: "geyacc version 3.4" + +class YMD_TIME_TOKENS + + +feature -- Last values + + last_any_value: detachable ANY + +feature -- Access + + token_name (a_token: INTEGER): STRING + -- Name of token `a_token' + do + inspect a_token + when 0 then + Result := "EOF token" + when -1 then + Result := "Error token" + when SCAN_ERROR_TOKEN then + Result := "SCAN_ERROR_TOKEN" + when WEEKDAY_TOKEN then + Result := "WEEKDAY_TOKEN" + when YEAR_TOKEN then + Result := "YEAR_TOKEN" + when MONTH_TOKEN then + Result := "MONTH_TOKEN" + when YEAR_OR_DAY_TOKEN then + Result := "YEAR_OR_DAY_TOKEN" + when NUMBER_TOKEN then + Result := "NUMBER_TOKEN" + else + Result := "Unknown token" + end + end + +feature -- Token codes + + SCAN_ERROR_TOKEN: INTEGER = 258 + WEEKDAY_TOKEN: INTEGER = 259 + YEAR_TOKEN: INTEGER = 260 + MONTH_TOKEN: INTEGER = 261 + YEAR_OR_DAY_TOKEN: INTEGER = 262 + NUMBER_TOKEN: INTEGER = 263 + +end diff --git a/jj_temporal/parsers/gobo_files/gelex.exe b/jj_temporal/parsers/gobo_files/gelex.exe new file mode 100644 index 0000000..73ef357 Binary files /dev/null and b/jj_temporal/parsers/gobo_files/gelex.exe differ diff --git a/jj_temporal/parsers/gobo_files/geyacc.exe b/jj_temporal/parsers/gobo_files/geyacc.exe new file mode 100644 index 0000000..316a799 Binary files /dev/null and b/jj_temporal/parsers/gobo_files/geyacc.exe differ diff --git a/jj_temporal/parsers/gobo_files/old_gelex.exe b/jj_temporal/parsers/gobo_files/old_gelex.exe new file mode 100644 index 0000000..bf7ed51 Binary files /dev/null and b/jj_temporal/parsers/gobo_files/old_gelex.exe differ diff --git a/jj_temporal/parsers/gobo_files/old_geyacc.exe b/jj_temporal/parsers/gobo_files/old_geyacc.exe new file mode 100644 index 0000000..f0c70b9 Binary files /dev/null and b/jj_temporal/parsers/gobo_files/old_geyacc.exe differ diff --git a/jj_temporal/parsers/gobo_files/y.bat b/jj_temporal/parsers/gobo_files/y.bat new file mode 100644 index 0000000..9e26023 --- /dev/null +++ b/jj_temporal/parsers/gobo_files/y.bat @@ -0,0 +1,7 @@ +cd d: +cd e_source +cd parser_tests +cd date_parser +cd discription_files +geyacc -t ymd_time_tokens -o ymd_time_parser.e ymd_time_parser.y +gelex -o ymd_time_scanner.e ymd_time_scanner.l diff --git a/jj_temporal/parsers/gobo_files/ymd_time_parser.y b/jj_temporal/parsers/gobo_files/ymd_time_parser.y new file mode 100644 index 0000000..2b06bf9 --- /dev/null +++ b/jj_temporal/parsers/gobo_files/ymd_time_parser.y @@ -0,0 +1,191 @@ +%{ +indexing + description: "[ + Parser for reading in a string and converting it to a date. + This file was produced by 'geyacc' (from the gobo tools cluster) + using file 'ymd_time_parser.y'. + ]" + date: "17 Aug 04" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class YMD_TIME_PARSER + +inherit + + YY_PARSER_SKELETON + rename + make as make_parser_skeleton + redefine + default_create + end + + YMD_TIME_PARSER_ROUTINES + rename + last_value as last_scanner_value + redefine + default_create + end + + YMD_TIME_SCANNER + rename + last_value as last_scanner_value + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create is + -- Create a new Eiffel parser. + do + Precursor {YMD_TIME_SCANNER} + make_parser_skeleton + end + +feature -- Access + + last_value: YMD_TIME + -- The result of parsing + +feature -- Basic operations + + parse_string (a_string: STRING) is + -- Parse `a_string'. + local + b: KL_CHARACTER_BUFFER + yy_buf: YY_BUFFER + f: FILE + s: STRING + do + reset + -- The `b' must end in "%U%U". I don't know why. + -- so append it onto the end of a copy of `a_string'. + s := deep_clone (a_string) + s.append ("%U%U") + create b.make_from_string (s) + create yy_buf.make_from_buffer (b) + set_input_buffer (yy_buf) + parse + end + +------------------------------------------------------------------------------------- +-------------------- Following created by GeYacc ---------------------------------- + + +%} + +%token SCAN_ERROR_TOKEN + +%token WEEKDAY_TOKEN +%token YEAR_TOKEN +%token MONTH_TOKEN +%token YEAR_OR_DAY_TOKEN +%token NUMBER_TOKEN + +%type Date +%type Ambiguous_day +%type Ambiguous_day_month +%type Unspecified +%type Weekday_included +%type Three_numbers +%type Two_numbers + +%type Month +%type Year +%type Year_or_day +%type Number + +-------------------------------------------------------------------------------- +%% + +Date: -- Empty { parsed_result := "No date entered" } + | Ambiguous_day { $$ := $1 last_value := $$ } + | Ambiguous_day_month { $$ := $1 last_value := $$ } + | Unspecified { $$ := $1 last_value := $$ } + | Three_numbers { $$ := $1 last_value := $$ } + | Two_numbers { $$ := $1 last_value := $$ } + | Weekday_included { $$ := $1 last_value := $$ } +-- | SCAN_ERROR_TOKEN { $$ := last_scanner_value last_value := $$ } + ; + +-- The Month and Year are known. +Ambiguous_day: Number Month Year { $$ := process_ambiguous_day ($1, $2, $3) } + | Year_or_day Month Year { $$ := process_ambiguous_day ($1, $2, $3) } + | Month Year_or_day Year { $$ := process_ambiguous_day ($2, $1, $3) } + | Month Number Year { $$ := process_ambiguous_day ($2, $1, $3) } + ; + +-- Only the Year is certain. +Ambiguous_day_month: Year_or_day Number Year { $$ := process_ambiguous_day ($1, $2, $3) } + | Number Year_or_day Year { $$ := process_ambiguous_day ($2, $1, $3) } + | Year Year_or_day Number { $$ := process_ambiguous_day ($2, $3, $1) } + | Year Number Year_or_day { $$ := process_ambiguous_day ($3, $2, $1) } + | Number Number Year { $$ := process_ambiguous_day_month ($1, $2, $3) } + | Year Number Number { $$ := process_ambiguous_day_month ($2, $3, $1) } + ; + +-- Two values input and at least one can be identified; assumptions are made about the unknowns. +Unspecified: Month Year { $$ := process_unspecified (0, $1, $2) } + | Year Month { $$ := process_unspecified (0, $2, $1) } + | Year_or_day Month { $$ := process_unspecified ($1, $2, 0) } + | Month Year_or_day { $$ := process_unspecified ($2, $1, 0) } + | Number Year { $$ := process_unspecified (0, $1, $2) } + | Year Number { $$ := process_unspecified (0, $2, $1) } + | Number Month { $$ := process_unspecified ($1, $2, 0) } + | Month Number { $$ := process_unspecified ($2, $1, 0) } + ; + +-- A date with the weekday included; the weekday is ignored. +Weekday_included: Weekday Ambiguous_day { $$ := $2 } + | Weekday Ambiguous_day_month { $$ := $2 } + | Weekday Unspecified { $$ := $2 } + | Weekday Three_numbers { $$ := $2 } + | Weekday Two_numbers { $$ := $2 } + ; + +-- The date is entered as three numbers and scanner is unable to deduce from +-- the values which one is day, year, and so on. +Three_numbers: Number Number Number { $$ := process_three_numbers ($1, $2, $3) } + | Year_or_day Number Number { $$ := process_three_numbers ($1, $2, $3) } + | Number Year_or_day Number { $$ := process_three_numbers ($1, $2, $3) } + | Number Number Year_or_day { $$ := process_three_numbers ($1, $2, $3) } + ; + +-- The date was enterred as only two numbers and the scanner was unable +-- to deduce thier meanings. +Two_numbers: Number Number { $$ := process_two_numbers ($1, $2) } + | Year_or_day Number { $$ := process_two_numbers ($1, $2) } + | Number Year_or_day { $$ := process_two_numbers ($1, $2) } + ; + + +-------------------------------------------------------------------------------- + +Weekday: WEEKDAY_TOKEN { -- do nothing as result is not needed + } + ; + +Month: MONTH_TOKEN { $$ := last_integer } + ; + +Year: YEAR_TOKEN { $$ := last_integer } + ; + +Year_or_day: YEAR_OR_DAY_TOKEN { $$ := last_integer } + ; + +Number: NUMBER_TOKEN { $$ := last_integer } + ; + + +%% + +end -- class YMD_TIME_PARSER diff --git a/jj_temporal/parsers/gobo_files/ymd_time_scanner.l b/jj_temporal/parsers/gobo_files/ymd_time_scanner.l new file mode 100644 index 0000000..293ebc2 --- /dev/null +++ b/jj_temporal/parsers/gobo_files/ymd_time_scanner.l @@ -0,0 +1,149 @@ +%{ +indexing + description: "[ + Scanner for reading in a string and converting it to a date. + This file was produced by 'gelex' (from the gobo tools cluster) + using file "ymd_time_scanner.l". + ]" + date: "17 Aug 04" + author: "Jimmy J. Johnson" + copyright: "Copyright 2009, Jimmy J. Johnson" + license: "Eiffel Forum License v2 (see forum.txt)" + URL: "$URL:$" + date: "$Date: 2009-06-25 21:37:23 -0400 (Thu, 25 Jun 2009) $" + revision: "$Revision: 7 $" + +class YMD_TIME_SCANNER + +inherit + + YY_COMPRESSED_SCANNER_SKELETON + export + {NONE} all + {ANY} scanning_error + redefine + default_create + end + + UT_CHARACTER_CODES + export + {NONE} all + redefine + default_create + end + + YMD_TIME_TOKENS + export + {NONE} all + redefine + default_create + end + + YMD_TIME_SCANNER_ROUTINES + export + {NONE} all + redefine + default_create + end + +create + default_create + +feature {NONE} -- Initialization + + default_create is + -- Create a scanner object + do + make + Precursor {YMD_TIME_SCANNER_ROUTINES} + end + +feature -- Basic operations + + scan_string (a_string: STRING) is + -- Scan `a_string' + local + b: KL_CHARACTER_BUFFER + yy_buf: YY_BUFFER + f: FILE + s: STRING + do + -- The `b' must end in "%U%U". I don't know why. + -- so append it onto the end of a copy of `a_string'. + s := deep_clone (a_string) + s.append ("%U%U") + create b.make_from_string (s) + create yy_buf.make_from_buffer (b) + set_input_buffer (yy_buf) + scan + end + + print_values is + do + io.put_string ("token = ") + io.put_string (token_name (last_token)) + io.put_string (" value = ") + if last_value /= Void then + io.put_string (last_value.out) + else + io.put_string ("Void") + end + io.new_line + end + +--------------------------------------------------------------------------------- +----------------------- Following code produce by Gelex ---------------------- + +%} + +--%x IN_STR -- line 50 +%option outfile="ymd_time_scanner.e" + + +IDENTIFIER [a-zA-Z][a-zA-Z]* + +DIGIT [0-9] +INTEGER {DIGIT}+|{DIGIT}{1,3}(,{DIGIT}{3})+ + +SEPARATORS [:./\\,\- \t\n\r]+ + +%% + +{INTEGER} { + last_integer := comas_removed (text).to_integer + last_value := last_integer + if last_integer > 31 then + last_token := YEAR_TOKEN + elseif last_integer > 12 then + last_token := YEAR_OR_DAY_TOKEN + else + last_token := NUMBER_TOKEN + end + print_values + } + +{IDENTIFIER} { if is_month (text) then + last_token := MONTH_TOKEN + last_integer := get_month (text) + last_value := last_integer + elseif is_weekday (text) then + last_token := WEEKDAY_TOKEN + last_string := text + last_value := text + else + last_token := SCAN_ERROR_TOKEN + last_value := last_string + print_values + end + print_values + } + +{SEPARATORS} { last_value := text + print_values + } + + +%% + + +end -- class YMD_TIME_SCANNER \ No newline at end of file diff --git a/setup.bat b/setup.bat new file mode 100644 index 0000000..0b8d78a --- /dev/null +++ b/setup.bat @@ -0,0 +1 @@ +set JJ_GITHUB=%~dp0 diff --git a/setup.rc b/setup.rc new file mode 100644 index 0000000..c43ad0b --- /dev/null +++ b/setup.rc @@ -0,0 +1 @@ +export JJ_GITHUB=`pwd`