Some Basics for a Time Class

 

Introduction.  In the previous webpage I discussed some issues associated with  classes contain most of the methods working with times. This webpage will focus on developing some basic methods for outputting and transferring between different time formats.  This is a modification of what Deitel and Deitel do in their book.  We will take their work a step further by developing a GUI for user interactions.

We will be representing time in a format

hh:mm:ss

where each

  • hh is a positive integer from 00 to 23

  • mm is a positive integer from 00 to 59

  • ss is a positive integer from 00 to 59

Our GUI will allow a user to enter the hours in one JTextField, minutes in another, and seconds in another.  Then the user's inputs will be echoed, displayed in AM/PM format and in universal time format on a 24 hour clock.  We will also develop a method to do some input validation.

For the next week we will enhance this class and its implementation in a variety of ways.

The TimeBasics Class.  The first set of code is used to create our class.  It will not be executed directly.  It will allow a developer to import its pre-existing capabilities in other programs.  You should save the  following program in ots own directory and call it TimeBasics.java.

 

import java.text.DecimalFormat;

// This class maintains the time in a 24 hour format
// and has a method to convert this to an AM/PM scale


public class TimeBasics extends Object
{

//  class instance variables
private int hour; // from 0 to 23
private int minute; // from 0 to 59
private int second; // from 0 to 59

// The TimeBasics constructor initializes each instance variable (instantiation of an object) to zero.
// It also ensures that each TimeBasics object starts in a state consistent with its specifications

public TimeBasics( )
{

setTime(0,0,0);

}

// Set a new time using military/universal representation.
// Perform validity checks on the data.
// Set invalid values to zero to ensure consistency.

public void setTime( int h, int m, int s)
{

// if hour number is outside the acceptable range set it to 0
if (h < 0 || h >= 24) hour = 0;
else hour = h;
// if minutes number is outside the acceptable range set it to 0
if (m < 0 || m >= 60) minute = 0;
else minute = m;
// if seconds number is outside the acceptable range set it to 0
if (s < 0 || s >= 60) second = 0;
else second = s;

}

// This method converts a time to a string in military/universal format
public String toUniversalString()
{

DecimalFormat twoDigits = new DecimalFormat("00");

return twoDigits.format(hour) + ":" + twoDigits.format(minute) + ":" + twoDigits.format(second);

}

// Convert string into AM/PM time format
public String toAMPMString( )
{

String AMPM;
int tempHour;
// setting up a decimal format to make certain numbers
// have two digits with no decimal places
DecimalFormat twoDigits = new DecimalFormat("00");
// checking for noon and midnight
if (hour == 12 || hour == 0)

tempHour = 12;

// if not noon or midnight then
// cast hour into correct number of hours
// since noon or midnight

else

tempHour = hour % 12;

// determine whether it is AM or PM by hour
if (hour < 12)

AMPM = "AM";

else

AMPM = "PM";

return tempHour + ":" + twoDigits.format(minute) + ":" + twoDigits.format(second) + AMPM;

}

public String echoInput( )
{

DecimalFormat twoDigits = new DecimalFormat("00");

return twoDigits.format(hour) + ":" + twoDigits.format(minute) + ":" + twoDigits.format(second);

}

}

 

This program needs to be compiled into a class using the statement

javac TimeBasics.java

this creates TimeBasics.class which can be used by other programs as long as these programs are in the same directory.  The next webpage will present how to create classes and place them into another directory and then access such classes from any other java program.  But we will leave this for the future.

The first thing you might notice about the code is there is no method main( ) or init( ).  Nothing in the program will cause it to execute.  But its compilation does create a class that is usable by other programs. 

The code does the following

  • imports the java.text.DecimalFormat classes
    • these will be used to prevent the appearance of decimal places and/or dropping digits if they are zeros
  • the overall inclusive class is called TimeBasics the same as the file
    • private integer instance variables for hour, minutes and seconds are declared at this level global to all other methods
      • every instance of a TimeBasics object will have an hour, minute and second

 

  • a TimeBasics( ) constructor that doesn't receive or return any values is declared and defined
    • notice it has exactly the same name as the class
    • it calls another method ands sets the time to be all zeros

 

  • a setTime( ) method is declared and developed
    • it receives three integer arguments
      • h  for the hours
      • m  for the minutes
      • s  for the seconds
    • an if statement is used to ensure the hours are within an acceptable range from 0 up to 23
      • if they aren't then the hours are set to zero
    • an if statement is used to ensure the minutes are within an acceptable range from 0 up to 59
      • if they aren't then the minutes are set to zero
    • an if statement is used to ensure the seconds are within an acceptable range from 0 up to 59
      • if they aren't then the seconds are set to zero

 

  • a toUniversalString( ) method is declared and developed
    • it develops a twoDigits format to ensure that the output terms have no decimal places and don't drop leading zeros
    • the format is developed for a 24 hour clock using hours:minutes:seconds  =  hh:mm:ss

 

  • a toAMPMString( ) method is declared and developed
    • it develops a twoDigits format to ensure that the output terms have no decimal places and don't drop leading zeros
    • the format is set up to report the clock time using an AM or PM denotation
    • an if statement on the hours is used to determine whether it is noon or midnight and adjust a local tempHour variable appropriately
    • if it isn't noon or midnight then the modulus operator is used to determine the number of hours since noon or midnight and assigned to tempHours
    • finally, based on the initial value for the hours an AMPM variable is
      • set to AM if hours is less than 12
      • set to PM if hours is 12 or greater

 

  • an echoInput( ) method is declared and developed
    • it develops a twoDigits format to ensure that the output terms have no decimal places and don't drop leading zeros
    • it returns what the user inputted except those that have been switched to zeros in setTime( ) if the inputted values are out of bounds
    • the format is developed for hours:minutes:seconds  =  hh:mm:ss

 

So, this is a fairly meager set of methods in a class, but it is a start and we will be able to use it to focus on other issues.  We will augment its functionality as we proceed through the next week.

A GUI for Testing TimeBasics.  Rather than create what seems to be a  bare minimum testing program as is done in Deitel and Deitel, we will implement a GUI to allow for user inputs.  This GUI will be an applet.  The applet will primarily involve developing the GUI, validating inputs, using the TimeBasics class to operate on the user's inputs and displaying the results on the GUI.  It's methods are constructed with these basic functionalities in mind.

You should call the file TimeBasicsTest.java.  Make sure it is in the same directory as the TimeBasics.class.

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TimeBasicsTest extends JApplet implements ActionListener
{

// declare GUI components
JLabel lblHoursInput;
JTextField txtHoursInput;
JLabel lblMinutesInput;
JTextField txtMinutesInput;
JLabel lblSecondsInput;
JTextField txtSecondsInput;
JLabel lblEchoInput;
JTextField txtEchoInput;
JLabel lblUniversalTime;
JTextField txtUniversalTime;
JLabel lblAMPMTime;
JTextField txtAMPMTime;
JLabel lblClickToCompute;
JButton compute;
JPanel panInterface;
// declare four global variables related to inputs
boolean validInput;
int hoursInput = 0;
int minutesInput = 0;
int secondsInput = 0;

public void init( )
{

JPanel panInterface = new JPanel();
panInterface = createGUI();

setContentPane(panInterface);

}

public void actionPerformed(ActionEvent userClick)
{

if (userClick.getSource( ) == compute)
{

// call method to obtain and validate input
validInput = validateInput( );
// perform computations only if method returns true
if (validInput)
{

// instantiate an object of type Circle
// with the valid radius inputted by the user

TimeBasics thisTime = new TimeBasics( );
thisTime.setTime(hoursInput, minutesInput, secondsInput);
// echo back the input to the user
txtEchoInput.setText(thisTime.echoInput( ));
// call the method to convert the inputs
// to universal time
// set the text in the appropriate JTextField

txtUniversalTime.setText(thisTime.toUniversalString( ));
// call the method to compute the circumference
// convert the numeric answer to a string
// set the text in the appropriate JTextField

txtAMPMTime.setText(thisTime.toAMPMString( ));
// a finalizer to free up memory allocation on TimeBasics thisTime
thisTime = null;

}

}

}

public JPanel createGUI( )
{

JPanel panGUI = new JPanel();
panGUI.setLayout( new GridLayout(7, 2, 5, 5) );

// developing input row for hours
lblHoursInput = new JLabel("Please input the hours: ", SwingConstants.RIGHT);
panGUI.add(lblHoursInput);

txtHoursInput = new JTextField(3);
panGUI.add(txtHoursInput);

// developing input row for minutes
lblMinutesInput = new JLabel("Please input the minutes: ", SwingConstants.RIGHT);
panGUI.add(lblMinutesInput);

txtMinutesInput = new JTextField(3);
panGUI.add(txtMinutesInput);

// developing input row for seconds
lblSecondsInput = new JLabel("Please input the seconds: ", SwingConstants.RIGHT);
panGUI.add(lblSecondsInput);

txtSecondsInput = new JTextField(3);
panGUI.add(txtSecondsInput);

// developing command button row for program execution
lblClickToCompute = new JLabel("Click button to solve: ", SwingConstants.RIGHT);
panGUI.add(lblClickToCompute);

compute = new JButton("Compute");
compute.addActionListener(this);
panGUI.add(compute);

// developing output row for echo of the input
lblEchoInput = new JLabel("Echoing your input: ", SwingConstants.RIGHT);
panGUI.add(lblEchoInput);

txtEchoInput = new JTextField(10);
txtEchoInput.setEditable(false);
panGUI.add(txtEchoInput);

// developing output row for universal time
lblUniversalTime = new JLabel("In universal time: ", SwingConstants.RIGHT);
panGUI.add(lblUniversalTime);

txtUniversalTime = new JTextField(10);
txtUniversalTime.setEditable(false);
panGUI.add(txtUniversalTime);

// developing output row for AM/PM time
lblAMPMTime = new JLabel("In AM/PM time: ", SwingConstants.RIGHT);
panGUI.add(lblAMPMTime);

txtAMPMTime = new JTextField(10);
txtAMPMTime.setEditable(false);
panGUI.add(txtAMPMTime);

return panGUI;

}

public boolean validateInput( )
{

String errorMessage = "";
validInput = true;

try
{

hoursInput = Integer.parseInt(txtHoursInput.getText());

}

catch (NumberFormatException nfeInteger)
{

// give error message when input can't be parsed to integer
errorMessage = errorMessage + "You need to enter an integer for the hour\n";
// set boolean variable to false when
// received an invalid input

validInput = false;
// blanking out inputs and any previous outputs
// when input is invalid

txtHoursInput.setText("");

}

try
{

minutesInput = Integer.parseInt(txtMinutesInput.getText());

}

catch (NumberFormatException nfeInteger)
{

// give error message when input can't be parsed to integer
errorMessage = errorMessage + "You need to enter an integer for the minutes\n";
// set boolean variable to false when
// received an invalid input

validInput = false;
// blanking out inputs and any previous outputs
// when input is invalid

txtMinutesInput.setText("");

}

try
{

secondsInput = Integer.parseInt(txtSecondsInput.getText());

}

catch (NumberFormatException nfeInteger)
{

// give error message when input can't be parsed to integer
errorMessage = errorMessage + "You need to enter an integer for the seconds\n";
// set boolean variable to false when
// received an invalid input

validInput = false;
// blanking out inputs and any previous outputs
// when input is invalid

txtSecondsInput.setText("");

}

if (!validInput)
{

JOptionPane.showMessageDialog(null, errorMessage, "Input Error", JOptionPane.ERROR_MESSAGE);
txtEchoInput.setText("");
txtUniversalTime.setText("");
txtAMPMTime.setText("");

}

return validInput;

}

}

 

Since I want you to run the program before we discuss it you should create the TimeBasicsTest.html.

 

<html>
<applet code="TimeBasicsTest.class" width=400 height=300>
</applet>
</html>

 

Now you should run the program and try different inputs.  If some input is non-integer you should get an error message appropriate to which are invalid like the following.

 

 

Assuming you enter acceptable numbers you should see something like the following.

 

 

You should be able to change the inputs and still get a stable set of interactions through this GUI based on your inputs since we have put in some error trapping.

Now we discuss the code which isn't much different than other GUI development and input handling you've already seen.  The only truly new code occurs in the actionPerformed( ) method where we instantiate a TimeBasics object, set its time based on the user's inputs and make use of the TimeBasics methods to display different time formats.

The discussion of the code follows.

  • the javax.swing.* package is imported
  • the java.awt.* package is imported
  • the java.awt.event.* classes are imported
  • the overall inclusive class extends JApplet and implements the ActionListener
    • JLabels are declared as instance variables of the class for the following
      • lblHoursInput
      • lblMinutesInput
      • lblSecondsInput
      • lblEchoInput
      • lblUniversalTime
      • lblAMPMTime
      • lblClickToCompute
    • JTextFields are declared as instance variables of the class for the following
      • txtHoursInput
      • txtMinutesInput
      • txtSecondsInput
      • txtEchoInput
      • txtUniversalTime
      • txtAMPMTime
      • txtClickToCompute
    • a JButton compute is declared
    • a JPanel panInterface is declared
    • instance variables for handling user inputs are declared
      • validInput which is true or false
      • an integer hoursInput initialized at 0
      • an integer minutesInput initialized at 0
      • an integer secondsInput initialized at 0

 

  • the init( ) method
    • instantiates the panInterface JPanel
    • builds it by setting it equal to the method createGUI( ) which returns a panel
    • sets the content pane of the applet to panInterface

 

  • the actionPerformed( ) method handles the user's click on compute
    • first it determines the source of the action
    • then it calls the validateInput( ) method
      • validates input
      • generates an error message
      • returns valid inputs
    • if validateInput returns a true for validInput
      • instantiate a new TimeBasics object called thisTime using the TimeBasics( ) constructor in TimeBasics.class
      • uses the setTime( ) method of the TimeBasics class to set the time to the user's valid inputs
      • uses the echoInput( ) method of the TimeBasics class to display the user's inputs in hh:mm:ss format in the txtEchoInput JTextField
      • uses the toUniversalString( ) method of the TimeBasics class to display the user's inputs in 24 hour hh:mm:ss format in the txtUniversalTime JTextField
      • uses the toAMPMString( ) method of the TimeBasics class to display the user's inputs in hh:mm:ss AM/PM format in the txtAMPMTime JTextField

 

  • the createGUI( ) method
    • returns a JPanel containing the GUI
    • as a GridLayout with
      • 7 rows
      • 2 columns
      • cell padding of 5 pixels
    • all of the above components are initialized and added to the panel
      • input JTextFields are editable by default
      • output JTextFields have their editable properties set to false
      • an actionListener is added to the compute button
    • the panel is returned to the calling location

 

  • the validateInput( ) method
    • initializes a blank errorMessage
    • initializes validInput to true
    • uses a try block to
      • get the text from txtHourInput
      • parse it as an integer
    • uses a catch block if it can't be parsed as an integer to
      • append a string to the errorMessage
      • set validInput to false
      • set the txtHourInput to blank
    • uses a try block to
      • get the text from txtMinutesInput
      • parse it as an integer
    • uses a catch block if it can't be parsed as an integer to
      • append a string to the errorMessage
      • set validInput to false
      • set the txtMinutesInput to blank
    • uses a try block to
      • get the text from txtSecondsInput
      • parse it as an integer
    • uses a catch block if it can't be parsed as an integer to
      • append a string to the errorMessage
      • set validInput to false
      • set the txtSecondsInput to blank
    • if validInput is false due to some input problem
      • the errorMessage is displayed using the showMessageDialog( ) method of the JOptionPane class
      • set the text of txtEchoInput to blank
      • set the text of txtUniversalTime to blank
      • set the text of txtAMPMTime to blank

 

You should play with this program some more and make certain you understand what class the methods are in.