In this section you will see how to use another standard Ada library package,
Ada.Calendar
.
In all Ada packages, the resources provided are listed in an Ada source file called the package specification. The package specification plays two roles: It describes the package to the compiler, and it serves as a "contract" with the programmer using it, telling this human user exactly what resources to expect. Some of the different kinds of resources provided by a package are
Ada's calendar package provides a number of useful resources relating to
dates and times.
Figure
3.2 shows a part of the specification for Ada.Calendar
; for
clarity we have listed only those services needed in this example. Appendix E
gives the entire specification for Ada.Calendar
.
Figure 3.2 Partial Specification of Package Ada.Calendar
PACKAGE Ada.Calendar IS -- standard Ada package, must be supplied with compilers -- provides useful services for dates and times -- type definitions TYPE Time IS PRIVATE; SUBTYPE Year_Number IS Integer RANGE 1901..2099; SUBTYPE Month_Number IS Integer RANGE 1..12; SUBTYPE Day_Number IS Integer RANGE 1..31; -- functions to get the current time and return its date components FUNCTION Clock RETURN Time; FUNCTION Year (Date : Time) RETURN Year_Number; FUNCTION Month (Date : Time) RETURN Month_Number; FUNCTION Day (Date : Time) RETURN Day_Number; -- Ada.Calendar provides many other interesting facilities; -- for clarity, these are omitted from this figure. END Ada.Calendar;
After the first line,
PACKAGE Ada.Calendar ISwhich indicates the beginning of a package specification, four type declaration statements are given. The line
TYPE Time IS PRIVATE;specifies
Time
as a PRIVATE
type, the details of whose values
are not known to the package user. We do not know a Time
value
explicitly because it is an internal value produced by the computer's real-time
clock; this internal value represents a year, calendar day, and time of day in
a single bit pattern. We will discuss PRIVATE
types in detail
later, especially in Chapter 10. For now, you need to know that because
Time
is a PRIVATE
type, the only way we can use
Time
values is to work with them according to the various
operations provided by Calendar
; you will see a few of these
operations in a short while.
Given a program preceded by a context clause
WITH Ada.Calendar;the declaration
Right_Now : Ada.Calendar.Time;declares a variable capable of holding a time value. The form
Ada.Calendar.Time
is similar to the form
Ada.Text_IO.New_Line
in that the name of the package is used to
qualify the use of the package resource: Time
is a resource
provided by Ada.Calendar
; New_Line
is a resource
provided by Ada.Text_IO
.
Returning to the specification of Ada.Calendar
in
Figure
3.2, the next three lines give declarations for years, months, and
days:
SUBTYPE Year_Number IS Integer RANGE 1901..2099; SUBTYPE Month_Number IS Integer RANGE 1..12; SUBTYPE Day_Number IS Integer RANGE 1..31;
Recall from Chapter 2 that a type consists of a set of values
and a set of operations on these values and that a subtype is a subset of the
original set of values, together with the full original set of operations. For
example, in declaring Month_Number
to be a subtype of
Integer
and giving its range as 1..12
, we are saying
that any variables of type Month_Number
can hold integer values
only in the range 1 through 12, inclusive. Similarly, variables of subtype
Day_Number
can hold integer values in the range 1 through 31,
inclusive. All of the operations on integers apply to values of these subtypes,
but if an operation attempts to store a value that is outside the declared
range, this operation is improper and a Constraint_Error
exception will be raised at run time.
In this text we will make frequent use of subtypes; they are a convenient way to inform the compiler--and the reader of a program--that certain variables have ranges that are restricted according to their intended use. Ada can then help us to avoid and recover from errors by checking that variables store numbers only of appropriate size.
The declarations
This_Year : Ada.Calendar.Year_Number; This_Month : Ada.Calendar.Month_Number; This_Day : Ada.Calendar.Day_Number;
declare variables of the three subtypes provided by
Calendar
. Again we have used qualified references; this is done to
remind both the compiler and the human reader of the package in which the
resources are defined.
Next we consider how to determine the current time of day in Ada. Returning
to the Calendar
specification in Fig. 3.2, the next line
FUNCTION Clock RETURN Time;
specifies a function called Clock
. Given
the declaration
Right_Now: Ada.Calendar.Time;then an assignment statement such as
Right_Now := Ada.Calendar.Clock;will be compiled into machine instructions that read the computer's internal clock, which delivers the current time of day and stores this time value in the variable
Right_Now
. The expression
Ada.Calendar.Clock
is a function call; we will see other
function calls shortly.
This value is not very useful to us in this form; for example, we cannot display a time value because its precise form is not available to us. But as the next three lines,
FUNCTION Year (Date: Time) RETURN Year_Number; FUNCTION Month (Date: Time) RETURN Month_Number; FUNCTION Day (Date: Time) RETURN Day_Number;
of the specification show, the package gives us operations to
extract the year, month, and day from the internal time value. Each of these
operations is a function with a single parameter Date
, which is of
type Time
. For example, if we declare a variable
This_Year : Ada.Calendar.Year_Number;the assignment statement
This_Year := Ada.Calendar.Year(Date => Right_Now);will store the current calendar year in
This_Year
.
Since Ada.Calendar.Year_Number
is an ordinary integer subtype,
ordinary integer operations can be performed on the value in
This_Year
; specifically, its value can be displayed. This function
call is analogous to an Ada.Text_IO
procedure call such as
Text_IO.Put(Item => FirstInitial);
in the sense that a value is being supplied to correspond to
the formal parameter. The formal parameter of Put
is called
Item
; the formal parameter of Year
is called
Date
.
In using the operations of Ada.Calendar
, we have no knowledge
of the details of how they perform. This is of no concern to us; the
"contract" embodied in the specification tells us what to expect, and this is
all we need to know.
SYNTAX DISPLAY
Simple Function Call Statement
variable := fname (actual parameters);
This_Month := Ada.Calendar.Month(Date => Right_Now); Right_Now := Ada.Calendar.Clock;
fname
.
The function fname
is called, and its returned value is stored in
variable
. During the function execution, the named actual
parameters are associated with the corresponding formal parameters.
=>
).
Therefore, strictly speaking the order of the actual parameters does not
have to match that of the formal parameters. It is nevertheless good practice
to list the actual parameters in an order corresponding to the order of the
formal parameters.Note that as the second example shows, functions can be defined to have no parameters at all. The number, order, and type of the parameters is, of course, determined by the writer of the function, not its user.
Case Study: Displaying Today's Date in "mm/dd/yy" Form
Let's use the knowledge gained in this chapter to solve the problem of displaying today's date.
Display today's date in the usual American form mm/dd/yy
; for
example, if today is October 21, 1995, we display 10/21/95
. If
today is July 8, 1996, we display 7/8/96
.
Today's date can be obtained from the computer's internal clock using theappropriate Ada calendar facilities to get a time value and then to extract the month, day, and year. These three values can then be formatted to give the desired display.
Problem Data Types:
We need only the type Time
and the subtypes
Year_Number
, Month_Number
, and
Day_Number
provided by the standard package
Ada.Calendar
.
Problem Inputs:
No inputs need to be entered by the user.
Problem Outputs:
Today's date, in the form mm/dd/yy
.
1. Get the current time value from the computer's clock.
2. Extract the current month, day, and year from the time value.
3. Format and display the date.
Step 2 Refinement
2.1. Extract the current month from the time value.
2.2. Extract the current day from the time value.
2.3. Extract the current year from the time value.
In step 3, we note that because the year is in the form yyyy
(for
example, 1989), we need to select the last two digits for formatting.
Step 3 Refinement
3.1. Find the last two digits of the year.
3.2. Format and display the current month, day, and year.
We can illustrate the steps in the refinement process with a diagram that shows the algorithm subproblems and their interdependencies. An example of such a diagram, called a structure chart, is shown in Figure 3.3.
Figure 3.3 Structure Chart for Formatting and Displaying Today's Date
As we trace down this diagram, we go from an abstract problem to a more detailed subproblem. The original problem is shown at the top, or level 0, of the structure chart. The major subproblems appear at level 1. The different subproblems resulting from the refinement of each level-1 step are shown at level 2 and are connected to their respective level-1 subproblem. This diagram shows that the subproblem Extract date values from time value is dependent on the solutions to the subproblems Extract month, extract day, and extract year. Because the subproblem Get current time is not refined further, there are no level-2 subproblems connected to it.
Structure charts are intended to show the structural relationship between the subproblems. The algorithm (not the structure chart) shows the order in which each step must be carried out to solve the problem.
In this case, no user inputs are provided to the program. The only thing to test is the correct extraction and formatting of the month, day, and year. It is easy to check whether the program produced the correct date; just look at an ordinary calendar.
Program3.6 shows the Ada program for this problem.
Program 3.6
WITH Ada.Text_IO; WITH Ada.Calendar; WITH Ada.Integer_Text_IO; PROCEDURE Todays_Date IS ------------------------------------------------------------------------ --| Finds and displays today's date in the form mm/dd/yy --| The date is gotten from PACKAGE Ada.Calendar --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ Right_Now : Ada.Calendar.Time; -- holds internal clock value This_Year : Ada.Calendar.Year_Number; -- holds current year This_Month : Ada.Calendar.Month_Number; -- holds current month This_Day : Ada.Calendar.Day_Number; -- holds current day Last_Two_Digits : Natural; This_century : CONSTANT Integer := 1900; BEGIN -- Todays_Date -- Get the current time value from the computer's clock Right_Now := Ada.Calendar.Clock; -- Extract the current month, day, and year from the time value This_Month := Ada.Calendar.Month(Date => Right_Now); This_Day := Ada.Calendar.Day (Date => Right_Now); This_Year := Ada.Calendar.Year (Date => Right_Now); -- Format and display the date Last_Two_Digits := This_Year - This_Century; Ada.Text_IO.Put (Item => "Today's date is "); Ada.Integer_Text_IO.Put (Item => This_Month, Width => 1); Ada.Text_IO.Put (Item => '/'); Ada.Integer_Text_IO.Put (Item => This_Day, Width => 1); Ada.Text_IO.Put (Item => '/'); Ada.Integer_Text_IO.Put (Item => Last_Two_Digits, Width => 1); Ada.Text_IO.New_Line; END Todays_Date;Sample Run
Today's date is 7/24/95
The
program begins with the appropriate context clauses, including one for
Calendar
. Variables for the time, month, day, and year are
declared. We need two more declarations:
Last_Two_Digits : Natural; This_Century : CONSTANT Natural := 1900;
to allow us to find the last two digits of the year, as you
will see in a moment. (The constant This_Century
will have to be
changed, and the program recompiled, on January 1, 2000.)
In the program body, the statements that get the clock value and extract the month and day were just discussed. Finally, the statement
Last_Two_Digits := This_Year - This_Century;
finds the last two digits of the year: If the current year is
1990, This_Year
gets the value 1990-1900, or 90, as desired.
Finally, the results are formatted and displayed using a sequence of
Put
statements from Text_IO
and
Ada.Integer_Text_IO
. Notice how the integer values are displayed
using a width of 1 to keep them "up against" the slashes.
TESTING
The sample run shows the correct date, correctly formatted.
Display today's date in the form MONTH dd, yyyy
.
This problem is similar to the previous one. In fact, it can be solved just bymodifying the previous algorithm. Package Ada.Calendar
gives us
only the number of the current month from 1 to 12, so we need to specify the
names of the months. We can do this with an enumeration type:
TYPE Months IS (January, February, March, April, May, June, July, August, September, October, November, December);
The current month can be displayed using an instance of
Enumeration_IO
, as in the colors program:
PACKAGE Month_IO IS NEW Ada.Text_IO.Enumeration_IO(Enum =>
Months);
All steps of the algorithm are the same, except for step 3.1. We do not need toselect the last two digits of the year because all four digits will be printed.
However, we need to find the name corresponding to the number of the current
month. Because the month is given from 1 to 12, and the positions of the names
are 0 to 11, subtracting 1 from the month will give us the right position in
Months
, from which we can find the month name using the
Val
attribute. If the month name is stored in a variable
Month_Name
of type Months
, we have
Month_Name := Months'Val(This_Month - 1);
The solution to this problem is shown in Program 3.7.
Program 3.7
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; WITH Ada.Calendar; PROCEDURE Todays_Date_2 IS ------------------------------------------------------------------------ --| Finds today's date and displays it in the form MONTH dd, yyyy --| An enumeration type is used for months --| The date is gotten from PACKAGE Ada.Calendar --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ TYPE Months IS (January, February, March, April, May, June, July, August, September, October, November, December); PACKAGE Months_IO IS NEW Ada.Text_IO.Enumeration_IO(Enum => Months); Right_Now : Ada.Calendar.Time; -- holds internal clock value This_Year : Ada.Calendar.Year_Number; -- holds current year This_Month : Ada.Calendar.Month_Number; -- holds current month This_Day : Ada.Calendar.Day_Number; -- holds current day Month_Name: Months; BEGIN -- Todays_Date_2 -- Get the current time value from the computer's clock Right_Now := Ada.Calendar.Clock; -- Extract the current month, day, and year from the time value This_Month := Ada.Calendar.Month(Date => Right_Now); This_Day := Ada.Calendar.Day (Date => Right_Now); This_Year := Ada.Calendar.Year (Date => Right_Now); -- Format and display the date Month_Name := Months'Val(This_Month - 1); Ada.Text_IO.Put (Item => "Today's date is "); Months_IO.Put (Item => Month_Name, Set => Ada.Text_IO.Upper_Case); Ada.Text_IO.Put (Item => ' '); Ada.Integer_Text_IO.Put (Item => This_Day, Width => 1); Ada.Text_IO.Put (Item => ','); Ada.Integer_Text_IO.Put (Item => This_Year, Width => 5); Ada.Text_IO.New_Line; END Todays_Date_2;Sample Run
Today's date is JULY 24, 1995
Copyright © 1996 by Addison-Wesley Publishing Company, Inc.