added jj_temporal source code

This commit is contained in:
Jocelyn Fiat 2024-06-19 15:01:51 +02:00
parent d551f35d2f
commit 4df573d730
93 changed files with 13000 additions and 1 deletions

@ -1 +0,0 @@
Subproject commit 8b8f6b7b3b39f254293920f4e5f0fb1ab5c1926b

7
jj_temporal/README.md Normal file
View File

@ -0,0 +1,7 @@
# jj_temporal
Eiffel date and time classes
Main classes: ![](docs/main_classes.png?raw=true)

View File

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

View File

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

View File

@ -0,0 +1,273 @@
note
description: "[
Notion of a time, such as <1 Jan 98> or <10:30 P.M.> or <the moment of creation>, 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

View File

@ -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 <sys/timeb.h>"
end
feature {NONE} -- `struct timeb' encapsulation
timeb_structure_size: INTEGER
-- Size of `struct timeb'.
external
"C macro use <sys/timeb.h>"
alias
"sizeof(struct timeb)"
end
time_t_structure_size: INTEGER
-- Size of `struct timeb'.
external
"C macro use <time.h>"
alias
"sizeof(time_t)"
end
tm_structure_size: INTEGER
-- Size of `struct tm'.
external
"C macro use <time.h>"
alias
"sizeof(struct tm)"
end
get_millitm (p: POINTER): INTEGER
-- Get `p->millitm'.
external
"C struct struct timeb access millitm use <sys/timeb.h>"
end
get_time (p, t: POINTER)
-- Get `p->time'.
external
"C inline use <sys/timeb.h>, <time.h>"
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 <time.h>"
alias
"localtime ((time_t *) $t)"
end
gmtime (t: POINTER): POINTER
-- Pointer to `struct tm' area in UTC.
external
"C inline use <time.h>"
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 <time.h>"
end
get_tm_mon (p: POINTER): INTEGER
-- Get `p->tm_mon'.
external
"C struct struct tm access tm_mon use <time.h>"
end
get_tm_mday (p: POINTER): INTEGER
-- Get `p->tm_mday'.
external
"C struct struct tm access tm_mday use <time.h>"
end
get_tm_hour (p: POINTER): INTEGER
-- Get `p->tm_hour'.
external
"C struct struct tm access tm_hour use <time.h>"
end
get_tm_min (p: POINTER): INTEGER
-- Get `p->tm_min'.
external
"C struct struct tm access tm_min use <time.h>"
end
get_tm_sec (p: POINTER): INTEGER
-- Get `p->tm_sec'.
external
"C struct struct tm access tm_sec use <time.h>"
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

122
jj_temporal/classes/timer.e Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="jj_temporal_demo" uuid="E55510BE-486F-4ED3-A6C5-1FCCECA93777">
<target name="jj_temporal_demo">
<root class="JJ_TEMPORAL_DEMO" feature="make"/>
<option warning="true" full_class_checking="false" is_attached_by_default="true" is_obsolete_routine_type="true" void_safety="all" syntax="standard">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="jj_temporal" location="..\jj_temporal.ecf" readonly="false">
<option is_obsolete_routine_type="true">
<assertions precondition="true"/>
</option>
</library>
<cluster name="demo" location=".\">
<file_rule>
<exclude>/.git$</exclude>
<exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule>
</cluster>
</target>
</system>

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
# jj_temporal
Eiffel date and time classes
Main classes: ![](docs/main_classes.png?raw=true)

View File

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

View File

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

View File

@ -0,0 +1,273 @@
note
description: "[
Notion of a time, such as <1 Jan 98> or <10:30 P.M.> or <the moment of creation>, 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

View File

@ -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 <sys/timeb.h>"
end
feature {NONE} -- `struct timeb' encapsulation
timeb_structure_size: INTEGER
-- Size of `struct timeb'.
external
"C macro use <sys/timeb.h>"
alias
"sizeof(struct timeb)"
end
time_t_structure_size: INTEGER
-- Size of `struct timeb'.
external
"C macro use <time.h>"
alias
"sizeof(time_t)"
end
tm_structure_size: INTEGER
-- Size of `struct tm'.
external
"C macro use <time.h>"
alias
"sizeof(struct tm)"
end
get_millitm (p: POINTER): INTEGER
-- Get `p->millitm'.
external
"C struct struct timeb access millitm use <sys/timeb.h>"
end
get_time (p, t: POINTER)
-- Get `p->time'.
external
"C inline use <sys/timeb.h>, <time.h>"
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 <time.h>"
alias
"localtime ((time_t *) $t)"
end
gmtime (t: POINTER): POINTER
-- Pointer to `struct tm' area in UTC.
external
"C inline use <time.h>"
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 <time.h>"
end
get_tm_mon (p: POINTER): INTEGER
-- Get `p->tm_mon'.
external
"C struct struct tm access tm_mon use <time.h>"
end
get_tm_mday (p: POINTER): INTEGER
-- Get `p->tm_mday'.
external
"C struct struct tm access tm_mday use <time.h>"
end
get_tm_hour (p: POINTER): INTEGER
-- Get `p->tm_hour'.
external
"C struct struct tm access tm_hour use <time.h>"
end
get_tm_min (p: POINTER): INTEGER
-- Get `p->tm_min'.
external
"C struct struct tm access tm_min use <time.h>"
end
get_tm_sec (p: POINTER): INTEGER
-- Get `p->tm_sec'.
external
"C struct struct tm access tm_sec use <time.h>"
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="jj_temporal_demo" uuid="E55510BE-486F-4ED3-A6C5-1FCCECA93777">
<target name="jj_temporal_demo">
<root class="JJ_TEMPORAL_DEMO" feature="make"/>
<option warning="true" full_class_checking="false" is_attached_by_default="true" is_obsolete_routine_type="true" void_safety="all" syntax="standard">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="jj_temporal" location="..\jj_temporal.ecf" readonly="false">
<option is_obsolete_routine_type="true">
<assertions precondition="true"/>
</option>
</library>
<cluster name="demo" location=".\">
<file_rule>
<exclude>/.git$</exclude>
<exclude>/.svn$</exclude>
<exclude>/CVS$</exclude>
<exclude>/EIFGENs$</exclude>
</file_rule>
</cluster>
</target>
</system>

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-21-0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-21-0 http://www.eiffel.com/developers/xml/configuration-1-21-0.xsd"
name="jj_temporal"
uuid="1C5069C0-C04D-4077-8193-FB226A11EEE7"
library_target="jj_temporal">
<target name="jj_temporal">
<root all_classes="true"/>
<option warning="warning" full_class_checking="true" is_attached_by_default="true" void_safety="all">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<cluster name="jj_temporal" location=".\" recursive="true">
<file_rule>
<exclude>/demo$</exclude>
<exclude>/.svn$</exclude>
<exclude>/.git$</exclude>
<exclude>/docs$</exclude>
</file_rule>
<file_rule>
<exclude>^/parsers/gobo_files$</exclude>
</file_rule>
</cluster>
</target>
</system>

View File

@ -0,0 +1,10 @@
note
description: "Summary description for {YMD_TIME_PARSER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
YMD_TIME_PARSER
end

View File

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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -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 <YMD_TIME> Date
%type <YMD_TIME> Ambiguous_day
%type <YMD_TIME> Ambiguous_day_month
%type <YMD_TIME> Unspecified
%type <YMD_TIME> Weekday_included
%type <YMD_TIME> Three_numbers
%type <YMD_TIME> Two_numbers
%type <INTEGER> Month
%type <INTEGER> Year
%type <INTEGER> Year_or_day
%type <INTEGER> 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

View File

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

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-21-0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-21-0 http://www.eiffel.com/developers/xml/configuration-1-21-0.xsd"
name="jj_temporal"
uuid="1C5069C0-C04D-4077-8193-FB226A11EEE7"
library_target="jj_temporal">
<target name="jj_temporal">
<root all_classes="true"/>
<option warning="warning" full_class_checking="true" is_attached_by_default="true" void_safety="all">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<cluster name="jj_temporal" location=".\" recursive="true">
<file_rule>
<exclude>/demo$</exclude>
<exclude>/.svn$</exclude>
<exclude>/.git$</exclude>
<exclude>/docs$</exclude>
</file_rule>
<file_rule>
<exclude>^/parsers/gobo_files$</exclude>
</file_rule>
</cluster>
</target>
</system>

View File

@ -0,0 +1,10 @@
note
description: "Summary description for {YMD_TIME_PARSER}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
YMD_TIME_PARSER
end

View File

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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -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 <YMD_TIME> Date
%type <YMD_TIME> Ambiguous_day
%type <YMD_TIME> Ambiguous_day_month
%type <YMD_TIME> Unspecified
%type <YMD_TIME> Weekday_included
%type <YMD_TIME> Three_numbers
%type <YMD_TIME> Two_numbers
%type <INTEGER> Month
%type <INTEGER> Year
%type <INTEGER> Year_or_day
%type <INTEGER> 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

View File

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

1
setup.bat Normal file
View File

@ -0,0 +1 @@
set JJ_GITHUB=%~dp0

1
setup.rc Normal file
View File

@ -0,0 +1 @@
export JJ_GITHUB=`pwd`