* Calendar_Utilities package (long posting)
@ 1990-07-06 13:49 David Emery
1990-07-06 21:37 ` Michael Feldman
0 siblings, 1 reply; 2+ messages in thread
From: David Emery @ 1990-07-06 13:49 UTC (permalink / raw)
Here's a package that might prove useful in doing those tricky date
calculations in Ada. As usual, if any bugs in this code are caught or
captured, I disavow any knowledge of (and responsibility for) their
actions.
dave emery
emery@aries.mitre.org
---------------
with Calendar;
package Calendar_Utilities is
subtype hours_number is integer range 0..23;
subtype minutes_number is integer range 0..59;
subtype seconds_number is integer range 0..59;
subtype decimal_seconds is duration range duration'(0.0) .. duration'(1.0);
-- date strings are of the form
-- year/mo/da hr:mn:sc.decimal
function image_of (time : Calendar.time)
return string;
function value_of (str : string)
return Calendar.time;
function image_size (time : Calendar.time)
return natural;
function years_in (time : Calendar.time)
return Calendar.year_number;
function months_in (time : Calendar.time)
return Calendar.month_number;
function days_in (time : Calendar.time)
return Calendar.day_number;
function seconds_in (time : Calendar.time)
return Calendar.day_duration;
-- duration strings are of the form
-- hr:mn:sc.decimal
function image_of (d : duration)
return string;
function value_of (str : string)
return duration;
function image_size (d : duration)
return natural;
procedure split (d : in duration;
hr : out hours_number;
min : out minutes_number;
sec : out seconds_number;
dec : out decimal_seconds);
function duration_of (hrs : hours_number;
min : minutes_number;
sec : seconds_number;
dec : decimal_seconds)
return duration;
function hours_in (d : duration)
return hours_number;
function minutes_in (d : duration)
return minutes_number;
function seconds_in (d : duration)
return seconds_number;
function decimal_seconds_in (d : duration)
return decimal_seconds;
function clock_string
return string; -- is image_of(Calendar.clock);
end Calendar_Utilities;
---------------
with Text_IO;
package body Calendar_Utilities is
use Calendar;
function two_digit_image (n : natural)
return string;
pragma inline (two_digit_image);
function to_integer (d : duration)
return integer;
pragma inline (to_integer);
no_number_found : exception;
procedure get_next_number
(str : string;
start : natural;
value : out integer;
next_char : out natural);
pragma inline (get_next_number);
function image_of (time : Calendar.time)
return string
is
year : year_number;
month : month_number;
day : day_number;
seconds : day_duration;
begin
split (time, year, month, day, seconds);
return integer'image(year)(2..5)
& '/' & two_digit_image(month)
& '/' & two_digit_image(day)
& ' ' & image_of(seconds);
end image_of;
function value_of (str : string)
return Calendar.time
is
answer : Calendar.time;
year : year_number;
month : month_number;
day : day_number;
seconds : day_duration;
start : natural := str'first;
begin -- year/mo/da hr:mn:sc.decimal
-- find year
get_next_number (str, start, year, start);
if (str(start) /= '/') then
raise constraint_error; -- format error
else
start := start + 1;
end if;
-- find month
get_next_number (str, start, month, start);
if (str(start) /= '/') then
raise constraint_error; -- format error
else
start := start + 1;
end if;
-- find day
get_next_number (str, start, day, start);
-- get seconds
seconds := value_of (str(start..str'last));
answer := Calendar.time_of (year, month, day, seconds);
return answer;
end value_of;
function image_size (time : Calendar.time)
return natural
is
year : year_number;
month : month_number;
day : day_number;
seconds : day_duration;
begin
Calendar.split (time, year, month, day, seconds);
-- year / mo / da hr:mn:sc.decimal
return 4 + 1 + 2 + 1 + 2 + 1 + image_size(seconds);
end image_size;
function years_in (time : Calendar.time)
return Calendar.year_number
is
year : year_number;
month : month_number;
day : day_number;
seconds : day_duration;
begin
Calendar.split (time, year, month, day, seconds);
return year;
end years_in;
function months_in (time : Calendar.time)
return Calendar.month_number
is
year : year_number;
month : month_number;
day : day_number;
seconds : day_duration;
begin
Calendar.split (time, year, month, day, seconds);
return month;
end months_in;
function days_in (time : Calendar.time)
return Calendar.day_number
is
year : year_number;
month : month_number;
day : day_number;
seconds : day_duration;
begin
Calendar.split (time, year, month, day, seconds);
return day;
end days_in;
function seconds_in (time : Calendar.time)
return Calendar.day_duration
is
year : year_number;
month : month_number;
day : day_number;
seconds : day_duration;
begin
Calendar.split (time, year, month, day, seconds);
return seconds;
end seconds_in;
function image_of (d : duration)
return string
is
hr : hours_number;
min : minutes_number;
sec : seconds_number;
dec : decimal_seconds;
int_decimal : integer;
begin
split (d, hr, min, sec, dec);
int_decimal := to_integer(dec);
return two_digit_image(hr)
& ':' & two_digit_image(min)
& ':' & two_digit_image(sec)
& "." & integer'image(int_decimal) -- get rid of leading space
(2..integer'image(int_decimal)'last);
end image_of;
function value_of (str : string)
return duration
is
hr, min, sec, decimal : integer;
start : integer := str'first;
integer_seconds : integer;
answer : duration;
begin -- hr:mn:sc.decimal
-- find hours
get_next_number (str, start, hr, start);
if (str(start) /= ':') then
raise constraint_error; -- format error
else
start := start + 1;
end if;
-- find min
get_next_number (str, start, min, start);
if (str(start) /= ':') then
raise constraint_error; -- format error
else
start := start + 1;
end if;
-- find sec
get_next_number (str, start, sec, start);
if (str(start) /= '.') then
raise constraint_error; -- format error
else
start := start + 1;
end if;
-- find decimal
get_next_number (str, start, decimal, start);
-- put it all together
integer_seconds := hr * (60*60) + min *60 + sec;
answer := duration(integer_seconds)
+ duration(decimal * duration(duration'delta));
return answer;
end value_of;
function image_size (d : duration)
return natural
is
decimal_size : integer;
begin -- hr:mn:sc.decimal
decimal_size := integer'image
(to_integer(decimal_seconds_in(d)))'length -1;
return 2 + 1 + 2 +1 + 2 + 1
+ decimal_size;
end image_size;
procedure split (d : in duration;
hr : out hours_number;
min : out minutes_number;
sec : out seconds_number;
dec : out decimal_seconds)
is
seconds : integer;
hr_local, min_local : integer;
begin
seconds :=integer(d);
if (duration(seconds) > d) then
seconds := seconds -1;
end if;
dec := d - duration(seconds);
hr_local:= seconds / (60*60);
seconds := seconds - (hr_local *(60*60));
min_local := seconds / 60;
sec := seconds - (min_local*60);
hr := hr_local; min := min_local;
end split;
function duration_of (hrs : hours_number;
min : minutes_number;
sec : seconds_number;
dec : decimal_seconds)
return duration
is
seconds : integer;
begin
seconds := (hrs * (60*60)) + (min * 60) + sec;
return duration(seconds) + dec;
end duration_of;
function hours_in (d : duration)
return hours_number
is
answer : integer;
begin
answer := (integer(d) /(60*60));
return hours_number(answer);
end hours_in;
function minutes_in (d : duration)
return minutes_number
is
answer : integer;
begin
answer := (integer(d) - (hours_in(d) * 60 * 60)) /60;
return minutes_number(answer);
end minutes_in;
function seconds_in (d : duration)
return seconds_number
is
answer : integer;
begin
answer := (integer(d) - (hours_in(d) *60*60) - (minutes_in(d)* 60));
return seconds_number(answer);
end seconds_in;
function decimal_seconds_in (d : duration)
return decimal_seconds
is
begin
return decimal_seconds(d - duration(integer(d)));
end decimal_seconds_in;
function clock_string
return string -- is image_of(Calendar.clock);
is
begin
return image_of (calendar.clock);
end clock_string;
-- private bodies
function two_digit_image (n : natural)
return string
is
begin
case n is
when 0..9 =>
return '0' & integer'image(n)(2);
when 10..99 =>
return integer'image(n)(2..3);
when others =>
raise constraint_error;
end case;
end two_digit_image;
function to_integer (d : duration)
return integer
is
begin
return integer(d * duration(1.0/duration'delta));
end to_integer;
procedure get_next_number
(str : string;
start : natural;
value : out integer;
next_char : out natural)
is
current : natural := start;
answer : integer := 0;
found_number : boolean := false;
begin
loop
if (current > str'last) then
exit;
end if;
case str(current) is
when ' ' | Ascii.ht =>
if found_number then
exit; -- terminates number
-- otherwise skip
end if;
when '0' .. '9' =>
found_number := true;
answer := answer * 10 +
(character'pos(str(current)) - character'pos('0'));
when '-' => -- negatives not allowed!!
raise constraint_error;
when others =>
exit;
end case;
current := current + 1;
end loop;
if found_number then
next_char := current;
value := answer;
else
raise no_number_found;
end if;
end get_next_number;
end Calendar_Utilities;
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: Calendar_Utilities package (long posting)
1990-07-06 13:49 Calendar_Utilities package (long posting) David Emery
@ 1990-07-06 21:37 ` Michael Feldman
0 siblings, 0 replies; 2+ messages in thread
From: Michael Feldman @ 1990-07-06 21:37 UTC (permalink / raw)
Dave Emery's calendar utilities package is really nice. A quick scan of it
reveals a small flaw that has bitten me and my students more than once: in
extracting the integer part of Calendar.Seconds(Calendar.Time) the package
is converting to predefined integer. This is not portable, because if it's
late in the day and integer'size = 16 (as is the case on PC's, usually),
the conversion will raise constraint_error. "Mainframe" Ada's generally use
32-bit integer, which is clearly bigger than 86400.0, but Meridian and
Janus both use 16-bit integer. Bad news here. My hack is to convert to
float first. I'm not sure what accuracy problems this might present if
you're working in fractions of a second, but you all get the idea.
Anybody got a cleaner hack than mine? Have a look at this code:
(obviously My_Int_IO is the usual instantiation for predefined integer).
I've tested on both Unix and PC Ada's.
(Please don't flame about the simple-minded repetitive calculations;
I broke it out so the novice could easily understand it).
WITH Text_IO;
WITH My_Int_IO;
WITH Calendar;
PROCEDURE TimeOfDay IS
CurrentTime : Calendar.Time;
SecsPastMidnight : Calendar.Day_Duration;
MinsPastMidnight : Natural;
Secs : Natural;
Mins : Natural;
Hrs : Natural;
BEGIN -- show time as hh:mm:ss, 24-hr time
CurrentTime := Calendar.Clock;
SecsPastMidnight := Calendar.Seconds(CurrentTime);
MinsPastMidnight := Natural(Float(SecsPastMidnight)/60.0 - 0.5);
Secs := Natural(Float(SecsPastMidnight) - 60.0 * Float(MinsPastMidnight));
Mins := MinsPastMidnight REM 60;
Hrs := MinsPastMidnight / 60;
My_Int_IO.Put (Item => Hrs, Width => 1);
Text_IO.Put (Item => ':');
IF Mins < 10 THEN
Text_IO.Put (Item => '0');
END IF;
My_Int_IO.Put (Item => Mins, Width => 1);
Text_IO.Put (Item => ':');
IF Secs < 10 THEN
Text_IO.Put (Item => '0');
END IF;
My_Int_IO.Put (Item => Secs, Width => 1);
Text_IO.New_Line;
END TimeOfDay;
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~1990-07-06 21:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1990-07-06 13:49 Calendar_Utilities package (long posting) David Emery
1990-07-06 21:37 ` Michael Feldman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox