Previous | Next | Table of Contents | Index | Program List | Copyright

8.3 System Structures: A Package for Calendar Dates

In Chapters 3 and 7 we discussed some of the uses of Ada's predefined package Ada.Calendar. This package provides many facilities for working with dates and times, but it does not provide a way to represent calendar dates that is suitable for reading and displaying. In this section we develop a specification for a simple package to give us a nicer form for dates, including procedures to read and display dates. In Chapter 10 we will refine this package to make it more capable and robust.

Specification for the Dates Package

The package specification is found in Program 8.3.

Program 8.3
Specification of SimpleDates package

WITH Ada.Calendar;
PACKAGE Simple_Dates IS
------------------------------------------------------------------------
--| Specification for package to represent calendar dates
--| in a form convenient for reading and displaying.
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: July 1995                                     
------------------------------------------------------------------------

  TYPE Months IS
    (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);

  TYPE Date IS RECORD
    Month: Months;
    Day:   Ada.Calendar.Day_Number;
    Year:  Ada.Calendar.Year_Number;
  END RECORD;

  PROCEDURE Get(Item: OUT Date);
  -- Pre:  None
  -- Post: Reads a date in mmm dd yyyy form, returning it in Item

  PROCEDURE Put(Item: IN Date);
  -- Pre:  Item is defined
  -- Post: Displays a date in mmm dd yyyy form

  FUNCTION Today RETURN Date;
  -- Pre:  None
  -- Post: Returns today's date

END Simple_Dates;
We want the SimpleDates package to provide a standard representation for the months of the year. We do this by giving an enumeration type Months representing the abbreviated names of the months:
    TYPE Months IS
	(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
We can now make use of this type and the day and year types provided by Ada.Calendar to define a record type for a date, using the month abbreviation for the month field, as follows:
    TYPE Date IS RECORD
	Month: Months;
	Day: Ada.Calendar.Day_Number;
	Year: Ada.Calendar.Year_Number;
    END RECORD;
We could have defined our own year and month number types, but we chose instead to use types that were already available to us in a predefined Ada package (instead of "reinventing the wheel"). The input program Get will read a date in the form
    OCT 31 1995
and the output program Put will display dates in this form as well.

One more operation is included: a function Today that returns a date record initialized with the date the program is being run. In other words, given a declaration

    D: SimpleDates.Date;
the statement
    D := SimpleDates.Today;
sets the fields of D to today's month, day, and year, respectively. Two things are noteworthy about this function. First, it is an example of a parameterless function; like Ada.Calendar.Clock, it requires no parameters. Second, the return type of the function is a record, namely, one of type Date.

Body of the Dates Package

Program 8.4 shows the body of package SimpleDates.

Program 8.4
Body of SimpleDates package

WITH Ada.Calendar;
WITH Ada.Text_IO;
WITH Ada.Integer_Text_IO;
PACKAGE BODY Simple_Dates IS
------------------------------------------------------------------------
--| Body for package to represent calendar dates
--| in a form convenient for reading and displaying.
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: July 1995                                     
------------------------------------------------------------------------

  PACKAGE Month_IO IS 
    NEW Ada.Text_IO.Enumeration_IO(Enum => Months);


  PROCEDURE Get(Item: OUT Date) IS

  BEGIN -- Get

    Month_IO.Get(Item => Item.Month);
    Ada.Integer_Text_IO.Get(Item => Item.Day);
    Ada.Integer_Text_IO.Get(Item => Item.Year);

  END Get;


  PROCEDURE Put(Item: IN Date) IS

  BEGIN -- Put

    Month_IO.Put (Item => Item.Month, Width=>1);
    Ada.Text_IO.Put(Item => ' ');
    Ada.Integer_Text_IO.Put(Item => Item.Day, Width => 1);
    Ada.Text_IO.Put(Item => ' '); 
    Ada.Integer_Text_IO.Put(Item => Item.Year, Width => 4);

  END Put;

  FUNCTION Today RETURN Date IS
 
    Right_Now  : Ada.Calendar.Time;     -- holds internal clock value
    Result       : Date; 
   
  BEGIN -- Today
 
    -- 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 
    Result.Month := Months'Val(Ada.Calendar.Month(Right_Now)- 1); 
    Result.Day := Ada.Calendar.Day  (Right_Now);
    Result.Year := Ada.Calendar.Year (Date => Right_Now);
 
    RETURN Result;

  END Today;

END Simple_Dates;
There are just two procedures, Get and Put. SimpleDates.Get expects its input to be in the form given above. It is not a robust procedure like the ones in Robust_Input ( Section 6.7) which prompt the user until correct input is entered; it is more like the predefined Get routines in Ada.Text_IO: If anything is wrong with the input, Get simply allows the exception to be passed back to the calling routine.

What can go wrong? The month, day, or year entered by the user can be badly formed or out of range, or the combination of month, day, and year can form a nonexistent date such as Feb 30 1995. A badly formed month, day, or year will result in Ada.Text_IO.Data_Error being raised by Months_IO; an out-of-range month or year will result in Constraint_Error being raised. This routine does not discover the case of a nonexistent date; a revised version of the package, to be developed in Chapter 10, will correct this shortcoming and add the desired robustness.

The procedure SimpleDates.Put displays a date in the MMM DD YYYY form. Also note how the function Today uses the package Ada.Calendar to produce today's date and return it to the caller. Program 8.5 shows a test of the Simple_Dates package. Because the package is not robust, we include an exception-handling loop in the test program.

Proram 8.5
Test of SimpleDates package

WITH Ada.Text_IO;
WITH Simple_Dates;
PROCEDURE Test_Simple_Dates IS
------------------------------------------------------------------------
--|                                                              
--| Program to test the Simple_Dates package
--|                                                              
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: July 1995                                     
--|                                                              
------------------------------------------------------------------------

  D: Simple_Dates.Date;

BEGIN -- Test_Simple_Dates

  -- first test the function Today
  D := Simple_Dates.Today;
  Ada.Text_IO.Put(Item => "Today is ");
  Simple_Dates.Put(Item => D);
  Ada.Text_IO.New_Line;

  LOOP

    BEGIN -- block for exception handler
      Ada.Text_IO.Put("Please enter a date in MMM DD YYYY form > ");
      Simple_Dates.Get(Item => D);
      EXIT; -- only if no exception is raised
    EXCEPTION
      WHEN Constraint_Error =>
        Ada.Text_IO.Skip_Line;
        Ada.Text_IO.Put(Item => "Badly formed date; try again, please.");
        Ada.Text_IO.New_Line;
      WHEN Ada.Text_IO.Data_Error =>
        Ada.Text_IO.Skip_Line;
        Ada.Text_IO.Put(Item => "Badly formed date; try again, please.");
        Ada.Text_IO.New_Line;
    END;

  END LOOP;
  -- assert: at this point, D contains a correct date record

  Ada.Text_IO.Put(Item => "You entered ");
  Simple_Dates.Put(Item => D);
  Ada.Text_IO.New_Line;

END Test_Simple_Dates;
Sample Run
Today is AUG 16 1995
Please enter a date in MMM DD YYYY form > mmm dd yyyy
Badly formed date; try again, please.
Please enter a date in MMM DD YYYY form > Dec 15 1944
You entered DEC 15 1944

Exercises for Section 8.3

Self-Check

  1. Can a client program that uses SimpleDates change the day field of a Date variable? For example, suppose the variable represents November 30, 1991. Can the client program change the 30 to a 31?


Previous | Next | Table of Contents | Index | Program List | Copyright

Copyright © 1996 by Addison-Wesley Publishing Company, Inc.