You are here:

C++/C++ program help

Advertisement


Question
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <time.h>


using namespace std;

int main()
{
   // = (num3&&num4) - (num1&&num2);
   // save this calc for later: hrIn + (hrOut/60.0);
         // same thing = num3 + (num4/60);
   // write an alogorithm to establish the steps to take to solve the problem
   //(1) Declare some variables to work with
 char fare;
 char choice = 'y';
 int hrIn, minIn, hrOut, minOut;          
 float hours;
 float minutes;
 float total_minutes;          
 double cost;
 double arrive;
 double depart;
 float charge;


 while (choice == 'y')
 {
   //(2) OUtput reqd info and user message

 cout << "This program will calculate a single, couple, or group "
      << "\nfare amount which is then owed by the customer for the trip.\n"
      << "\nTo calculate a single fare amount, input S (or s)"
      << "\nTo calculate a couple fare amount, input C (or c)"
      << "\nTo calculate a group fare amount, input G (or g)"
      << " \n\nInput S, C, or G: ";
 cin >> fare;
  
 if(fare=='S'||fare=='s')
 {
  cout << "\nWhat hour did they depart? ";
  cin >> hrIn;
  cout << "\nWhat minute did they depart? ";
  cin >> minIn;
  cout << "\nYou entered for departure: " << hrIn << ":" << minIn << endl;
  cout << "\nWhat hour did they arrive? ";
  cin >> hrOut;
  cout << "\nWhat minute did they arrive? ";
  cin >> minOut;
  cout << "\nYou entered for arrival: " << hrOut << ":" << minOut << "\n" << endl;
  cout << "A rickshaw departed at " << hrIn << ":" << minIn
       << " and arrived at " << hrOut << ":" << minOut << " with a single customer.\n" << endl;
       
  float hours = hrOut - hrIn;
  cout << "You arrived in " << hours << " hour(s)";
  float minutes = minOut - minIn;
  cout << " and " << minutes << " minute(s)";
  float total_minutes = (hours * 60) + minutes;
  cout << ", or in " << total_minutes << " minutes.\n" << endl;
  
  
    if(total_minutes <= 30.0)
   {
       cout << fixed << showpoint << setprecision(2);
       
       charge = 7.00;
       
       cout << "You owe $" << charge << " dollars.\n" << endl;  
   }
   else if(total_minutes > 30.00 && total_minutes <=1440.0)
   {
        cout << fixed << showpoint << setprecision(2);
        
        charge = 7.00 + (((total_minutes) - 30) * 1.50);
   
        cout << "You owe $" << charge << " dollars.\n" << endl;  
}
   
}  
       }
       
// end of S if

//----------------------------------------------------

 
 
    system("pause");
    return 0;
}
    
  
**** I want to know how to write and input a time such that in the output:
      6:31 - 4:43 = 1 hour and 48 minutes instead of 2 hours and -12 minutes.

Also how would you write the time in a 12 Hour standard time of am/pm compared to 24 Hour military time?

Answer
Well nice to see you are moving forward and have moved from using hours with the minutes as fractions of an hour to using minutes. However if you are using whole minute values why do you need to use floating point values to store them? And why use a single precision float type?

Here are some facts about data type sizes for C++ built in arithmetic types for common 32-bit compilers:

   char          8-bits,        size  = 1 (by language definition)
   wchar          16 or 32 bits,  size  = 2 or 4
   short int       16-bits,        size  = 2
   int          32-bits,        size  = 4
   long int        32-bits,        size  = 4
  [long long int   64-bits,        size  = 8  -- currently a non-standard type]
   float          32-bits,        size  = 4
   double          64-bits,        size  = 8
   long double   >=64-bits,        size >= 8

So a float has the same number of bits as an int for current popular 32-bit compilers BUT a float has to store not only the value of the digits (the mantissa) but also the scale (the exponent), and so has LESS precision when used as an integer than the plain int type.

Hence I suggest you change all variables that store the time as whole numbers of minutes to being plain int type variables, either that or use a double (meaning double precision) floating point type for them.

Of course as even the number of minutes in a day is quite small (1440) you will probably not run into even the limits of a 32-bit float's (integer) precision in this case - but you may do if you do similar things for different problems in the future. (The most popular 32-bit format for floating point has only 23-bits of precision, one for the sign and 8-bits for the exponent. Hence if used for integer values they can store values in the range of approximately -8 million to +8 million, whereas a 32-bit int can store values in the range approximately -2 billion to +2 billion.)

Oh and as this is the second posting I would like to ask if you can take some time to clean up the formatting of your code. The brace placement and indentation of the code seems a bit all over the place:

   int main()
   {
     char fare;

     ...

     while (choice == 'y')
     {
     cout << "This program will calculate a single, couple, or group "
         << "\nfare amount which is then owed by the customer for the trip.\n"

     ...

     if(fare=='S'||fare=='s')
     {
      cout << "\nWhat hour did they depart? ";

      ...   

        if(total_minutes <= 30.0)
       {
         cout << fixed << showpoint << setprecision(2);

         ...
       }
       else if(total_minutes > 30.00 && total_minutes <=1440.0)
       {
         cout << fixed << showpoint << setprecision(2);

         ...
   }

   }  
         }

   // end of S if

   //----------------------------------------------------



        system("pause");
        return 0;
   }

This may of course have been as a result of posting through AllExperts. However if not then I would have thought it would have been easier to see what your code is doing if you indented blocks consistently and lined up opening and closing braces:

   int main()
   {
       char fare;

       ...

       while (choice == 'y')
       {
         cout << "This program will calculate a single, couple, or group "
         << "\nfare amount which is then owed by the customer for the trip.\n"

         ...

         if(fare=='S'||fare=='s')
         {
         cout << "\nWhat hour did they depart? ";

         ...   

         if(total_minutes <= 30.0)
         {
         cout << fixed << showpoint << setprecision(2);

         ...
         }
         else if(total_minutes > 30.00 && total_minutes <=1440.0)
         {
         cout << fixed << showpoint << setprecision(2);

         ...
         }

         }  
       }

       system("pause");
       return 0;
   }

Please ensure any code you post in the future at least starts out in such a well formatted state - if not I may well just look at your code an reject your question as I do not like wasting my time untangling messy code just so I can see what is going on - I am a volunteer expert, and I do have other things to get on with. So please make it as easy for me to understand any code you post by making sure it is well formatted an laid out. Also in general remove any commented out lines of code as I do not need to know about them - they are just clutter.

OK so that is probably enough on general points on your code.

So to your questions:

I am surprised you have not thought of the answer yourself as you seem to have worked out how to convert a time in two parts: hours and minutes_past_the_hour to the equivalent minutes_past_midnight:

   minutes_past_midnight = hours*60 + minutes_past_the_hour;

If you did this for each of your two part times:

   minsPastMidnightIn  = hrIn*60  + minIn;
   minsPastMidnightOut = hrOut*60 + minOut;

   minsDuration = minsPastMidnightOut - minsPastMidnightIn;

This will give you the duration in minutes, and will only be negative if the end time is before the start time - e.g. they left at 23:45 one day and arrived at 00:15 the next. In this case the duration should be 30 minutes but will in fact be -1410 minutes. In such cases adding 24hrs (i.e. 1440 minutes) should correct the value. You will have to consider if this is more likely than the user making an error (or is deliberately messing about!) - i.e. whether you want to handle cross midnight journeys or treat end times before start times as an error.

You can recover the hours and minutes duration values from the minsDuration value by using integer division and using the division and remainder values. In C and C++ we can get integer division remainder values (also called the modulus) by using the % operator:

   hrsDuration          = minsDuration / 60;
   minsPartOfHrDuration    = minsDuration % 60;

I will mention that modulus (remainder) operations are useful in more places than you might think.

In general when using time it is usually best to work in nice 'flat' values like minutes or seconds or whatever the smallest resolution required is (milliseconds, nanoseconds etc.) and convert composite times such as YYYY-mm-dd hh:MM:ss (where you end up with separate year, month, day, hour, minute and seconds values) into such a 'flat' value, such as number of seconds since some point in the past and then only convert such values back to composite date and time values when required. Another wrinkle with handling times are time zones - but let us leave that for another time (no pun intended!).

The reason for doing this - as we saw above - is that using a flat value of minutes or seconds makes it much easier to perform arithmetic on times!

Now I see that you are including time.h - by the way the C++ name for this header, like the cmath header (which is spelt math.h in C) is ctime.

This header includes declarations etc. for the C library date and time support. Standard C++ has no specific date and time handling of its own so we have to look to the C support for these facilities - ho hum.

Now be warned that use of this support requires knowledge of C (and C++) features you probably have not covered yet, and I do _not_ have time to teach them to you - this is _not_ a forum for full on courses and I am _not_ a professional educator in any case - oh and just formulating this reply is taking several hours. So I shall mention the features here in brief (along with a few that are also used in my example code) and expect you to look them up in your own time if you have not covered them yet:

   Type aliases: typedef
   C style user defined compound types (as used in C++): struct
   Use of pointers:    * to declare type is a pointer to some other type,
         * used to de-reference a pointer to obtain value of what is pointed at
         & used to obtain a pointer to a variable ('address of' operator)
   C style strings:    array types in general and zero character terminated arrays of char that
         C uses as its string type.
   Type conversions:   static_cast (C++ specific)

Now there are 2 types that are declared by ctime that are of interest here:

time_t is a type alias (typedef) for some 'arithmetic type' used to represent times. Although not mandated by the C or C++ standard time_t is usually an alias for an integer type.

To hold parts of a date and time ctime declares the tm struct type which has the following fields:

   int tm_sec; // seconds after the minute - [0, 60]
   int tm_min; // minutes after the hour - [0, 59]
   int tm_hour; // hours since midnight - [0, 23]
   int tm_mday; // day of the month - [1, 31]
   int tm_mon; // months since January - [0, 11]
   int tm_year; // years since 1900
   int tm_wday; // days since Sunday - [0, 6]
   int tm_yday; // days since January 1 - [0, 365]
   int tm_isdst; // Daylight Saving Time flag

In addition ctime declares several functions that work with time_t and tm types. For example the time function returns the current calendar time as a time_t. The encoding of the meaning of the values of a time_t returned by time are not specified by the standard but often the time_t values represent seconds past since some time in the past called the epoch. The epoch is commonly 00:00:00 UTC, January 1, 1970 (UTC is a basically GMT - Greenwich Mean Time - that is Greenwich in the UK, through which the 0 degree meridian passes).

Of particular interest here is the mktime function. This takes a time in parts (called a 'broken down time' in the C 1999 ISO standard) in a tm struct object and returns the time_t value that represents the date and time specified by the field values of the tm struct argument.

We could use mktime with your code to obtain time_t values for your program's start and end hour, minute values (note that mktime takes a pointer to a tm type object):

         timePartsIn.tm_hour = hrIn;
         timePartsIn.tm_min = minIn;

         timePartsOut.tm_hour = hrOut;
         timePartsOut.tm_min = minOut;

         time_t timeIn  = mktime(&timePartsIn);
         time_t timeOut = mktime(&timePartsOut);

Which assumes that timePartsIn and timePartsOut are tm struct types. Now there is a problem with timePartsIn and timePartsOut in that they both need to be explicitly set to some valid tm struct state before we use them for real - note that some of the fields of the tm struct leave questions as to what they should be even if we want a value for some sort of zero time - e.g. the Epoch date and time that time_t values returned by time assume. What day of the week was this date? And we have to set the year since 1900 value correctly and the day of the month - so we cannot just set all field values to zero to represent a zero date - doh!

Luckily for us there are two functions that give us access to a tm struct set of vales for a given time_t value: gmtime, which assumes the time_t represents UTC (i.e. Greenwich Mean time), and localtime which assume the time_t value represents time in the current local time zone. As your program is not that concerned with dates we can use gmtime. Hence we could define and initialise timePartsIn and timePartsOut to our zero time as follows (which goes before the code shown above). Again note the use of pointers with these functions.

         time_t zeroTime(0);
         tm * zeroTimePartsPointer(gmtime(&zeroTime));
         tm timePartsIn( *zeroTimePartsPointer );
         tm timePartsOut( *zeroTimePartsPointer );

The idea is as follow:
   - first obtain the tm struct representing our zero time.
       This is done by passing the address of a 0 time_t valued variable
       to gmtime and storing the value of the returned pointer to a tm struct.
   - Next we use the values of the zero time tm struct to copy-initialise
       the timePartsIn and timePartsOut tm struct objects. In C++ this is
       not done using pointers so we have to de-reference the
       zeroTimePartsPointer to obtain a reference to the tm struct pointed at.

OK so now we have your hour/minute times as 'flat' time_t values we can calculate the difference between them. There is another function provided to do this called difftime which we can use. Interestingly it returns the difference between two time_t values as a double - presumably because the maximum difference could exceed the range of values some time_t representations can handle and a double would generally extend this range:

         double durationTimeSecs( difftime(timeOut, timeIn) );

For once there is no use of pointers!

Now once we have time as time_t or tm (as we can move between them) we can use the provided functions for formatting time output. The easiest to use are asctime and ctime.

The asctime function takes a pointer to a tm struct and returns a pointer to a C string (zero terminated array of char) which is a string representing that date and time in the format:

   Sun Sep 16 01:03:52 1973\n\0

Where \n is a newline character and \0 is a (C string terminating) zero character.

The ctime function takes a pointer to a time_t time value and is equivalent to:

   asctime(localtime(timer))

where timer is a pointer to a time_t variable.

However if you want precise control over the format of the returned date and time string then we have to bring out the big guns: the strftime function.

The (simplified) declaration for strftime is as follows:

   size_t strftime(char * s, size_t maxsize, const char * format, const struct tm * timeptr);

In which size_t is another type alias for an unsigned integer type used to represent size of things such as number of elements in an array - which translates to number of characters in a C string (sometimes including the terminating zero and sometimes not - hence it is important to read the small print of such functions' usage and requirements).

Note that char * indicates a modifiable character buffer (i.e. a C-string) and const char * a non-modifyable char buffer (i.e. a C-string).

OK so the idea is that strftime takes a time value (the timeptr tm struct pointer parameter), and a string indicating the format of the required output (the format const char * parameter) and pointer to a character buffer in which to write the characters of the formatted date/time (the s char * parameter). The maxsize parameter specified how many characters can be written to in the provided s buffer.

The returned value is the number of characters written into the s buffer less the terminating zero or (importantly) zero if more characters would have been written than maxsize indicated could be used. We could use strftime like so:

         const size_t MaxChars(16);      // used to size output string buffer and for strftime maxsize
         char timeCString[MaxChars];     // C string output buffer for time

         time_t durationTimerSecs( static_cast<time_t>(durationTimeSecs) );

         size_t numCharsWritten( strftime(timeCString, MaxChars, format, gmtime(&durationTimerSecs)) );

Note that I have had to cast the double durationTimeSecs back into a time_t value durationTimerSecs so I can pass a pointer to this variable to gmtime to convert the duration to a tm struct value. I could have just created durationTimerSecs from durationTimerSecs:

         time_t durationTimerSecs( durationTimeSecs );

But would probably have had to put up with the compiler warning that data could be lost as converting from a double to int is a potentially lossy conversion.

The only part of the puzzle remaining is what do we place in the format C string argument? The answer to that depends on what format you want your date or time as a string to be in. In this case we are only interested in the time so we want either 24 hour or 12 hour time with am/pm indication. The description of strftime is very long as it describes in detail all the various special character sequences used to represent the parts of date and time to place into the output string (see for example:

   http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
).

In this case we are interested in time parts only. We have the sequences:

   %H      24 hour clock hour (0 - 23)
   %I      12 hour clock hour (0 - 11)
   %M      Minute past the hour (0 - 59)
   %p      AM/PM designations.

Notice that 12 hour time with a AM/PM designation is only really useful for absolute time of day not for time durations as you wish to output here.

So to output the hours and minutes of duration (assuming less than 1 day duration of course) I suggest you use the 24 hour format string:

   "%H:%M"

Hence we get:

         size_t numCharsWritten( strftime(timeCString, MaxChars, "%H:%M", gmtime(&durationTimerSecs)) );

We can then output the resultant string:

         if ( numCharsWritten!=0 )
         {
         cout << "Duration of journey was " << timeCString << endl;
         }
         else
         {
         cerr << "Oops! strftime failed. Not enough room for all date-time string characters"
         << endl;
         }

This is all very well but it does not help with your need to input the time in 12 hour format. Unfortunately there is no help for formatted time value entry in either the C++ or C standard libraries :(

So for this you have to do the work yourself.

The simplest scheme to implement with your current program setup is probably to check to see if the hours values entered are between 0 and 11 and if they are ask whether they are am or pm and if pm ad 12 to the value, e.g.:

         cout << "\nWhat hour did they depart? ";
         cin >> hrIn;
         cout << "\nWhat hour did they depart? ";
         cin >> hrIn;
         if ( hrIn < 12 )
         {
         char a_or_p('x');
         do
         {
         cout << "Is that " << hrIn << "am or " << hrIn << "pm (enter a or p)? ";
         cin >> a_or_p;
         if ( a_or_p == 'p' )
         {
         hrIn += 12;
         }
         else if ( a_or_p != 'a' )
         {
         cout << "Please enter a or p for am or pm.\n";
         }
         }
         while ( a_or_p != 'a' && a_or_p != 'p' );
         }

If you really want to parse dates and times in various formats then that is a topic (and assignment) all of its own - so maybe start off simply first eh?

However you could read values on a line one part at a time:

   cin >> hours >> separator >> minutes;
   
For example where hours and minutes are ints and separator is a char. This would allow you to read 11:45 or 15:59 or even 99999v1234

So you would then have to check you have the expected values in the required range - something you should be doing for your hour and minute read values at the moment by the way. That is hours values are >= 0 and <= 23 (or 11 for 12 hour time formats) and that minute variables are >=0 and <=59. You should also check that separators are the expected character for your format (e.g. == ':' ), and that for 12 hour values you read am or pm:

   cin >> hours >> separator >> minutes >> ampm;

The ampm variable would probably best being a C++ string type (include <string>):

   string ampm;

The C++ string type is a C++ class type and is well behaved and takes care of lots of niggly details that you have to otherwise worry about if you use C string zero terminated chars. For example with a C++ string object such as ampm you can write:

   if ( ampm=="pm" )
   {
       hours += 12;
   }
   else if ( ampm != "am" )
   {
       cout << "Please enter am or pm to specify which half of the day the time represents.\n";
   }

Which you cannot do for C string arrays (you have to use strcmp and check the returned value is (or is not) 0 indicating the C strings passed to it are the same (or not).

Oh and you should check that the cin stream is OK after every read. If it is not good then it is either hosed beyond recovery, at the end of the file (which should not happen if reading from the console!) or the previous operation failed - which if it was a formatted read as we have being using here is usually because you entered badly formatted data for the expected type - e.g. letters starting an int value. Again I shall let you look up how to check and clear the states of streams such as cin in your own time as I think this answer has gone on long enough (4+ hours long).

Anyway hope this helps and gives you some stuff to research for yourself.

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.