We realize that a calendar program we are helping build is going to is going to have to store and work with times of the day. We have been put in charge of writing the Time class to manage those.
Believe it or not, the first approach is a common approach for representing time in computers. But we will use the second option, which will make it easier to work in terms of hours and minutes.
What should we do if someone asks to make Time t1(11, 95)? Should we turn that into 12:35? Or should we treat that as an error and throw an exception? This is a design choice. Assuming that we should try to fix the issue can make the class a little more flexibleβit might be nice to be able to specify Time(0, 190) and get 3:10. But it could also lead to confusion. A value of 190 for minutes could be the result of a bug elsewhere and βfixingβ it automatically in Time, could hide the existence of that bug.
Instead of trying to fix the issue, we could instead use an exception to indicate there was a problem and require the caller to deal with the issue. This stricter approach can help catch errors earlier.
Time::Time(int hours, int minutes) {
if(hours < 0 || hours > 23) {
throw logic_error("Invalid value for hours");
}
if(minutes < 0 || minutes > 59) {
throw logic_error("Invalid value for minutes");
}
m_hours = hours;
m_minutes = minutes;
}
This would work just fine. But we will likely need similar code elsewhere. Maybe we should build a function that checks if a given time is valid. We could then use that function to help check the time we are trying to construct.
Time::Time(int hours, int minutes) {
// check the values, throw an exception if they are invalid
validate(hours, minutes);
// otherwise safe to use them
m_hours = hours;
m_minutes = minutes;
}
Next letβs tackle getting string representations of the time. We want to be able to generate either a 12 hour or 24 hour format. Before we write the functions, we will set up some tests:
string Time::toString24Hour() {
// minutes should always be 2 digits, use 0 to pad
string tString = format("{}:{:0>2}", m_hours, m_minutes);
return tString;
}
Next we need to decide how and if to support changing the time. One approach would be to make Time objects immutable, or unchangeable. If we do not provide setters, or any other methods to change the member variables of a Time, it will be impossible for other code to modify a Time. Instead, anytime we want to change a time, we would need to make a a new Time object. Making Time objects immutable can make it safer to work with Times. If they canβt be changed, we can pass around Time objects by reference without having to worry about them being changed.
But we decide we will support modification of Time objects. Then the question becomes how to do so. Do we provide setters for both hours and minutes? Do we provide a function that sets both to new values? We could just provide one or the other option, but it will be more convenient for users of the class if they can just chose to update either the hour or the minute, or both, with a single call.
Letβs provide functions to change both members as well as both at the same time. They can all use our existing validate function to make sure that the provided values make sense. When we are only given one value, we can pass validate a dummy value that we know is valid for the other one.
If main wants to add 30 minutes to a Time, it should not have to getMinute, do math, and then do setTime (and possibly setHour) to do so. So letβs add a function to Time that does that work.
void Time::addMinutes(int minutes) {
---
m_minutes += minutes;
---
// if minutes is now greater than 59,
// wrap and update the number of hours
if (m_minutes > 59) {
---
m_hours += m_minutes / 60;
m_minutes = m_minutes % 60;
---
}
---
// if hours is now greater than 23
// fix it
if (m_hours > 23) {
m_hours = m_hours % 24;
}
---
}
We certainly could add more functionality to the Time class, such as support for different time zones or the ability to compare two times. And we need to add comments to our class. However, we will stop here. You can find the complete code for the Time class as a module and as a .h/.cpp file pair in the appendix for this chapter.