Calendar program for C++ class has a day counting bug - c++

I am making a calendar program in C++ that determines the days of a month in any given year by counting the number of days between January 1st, 1753 all the way to the first day of the given month in the given year. It then divides this number of days by 7 to determine the "offset" that is used to figure out what day the first day of the month begins (example: since January 1st, 1753 is on a Monday, an offset of 2 means that the first day of the month will be on a Wednesday). I completed my code and ran it through several tests when I noticed a very strange bug. For the year 2000, the offset is one higher than it should be (February starts on a Wednesday instead of a Tuesday, etc). This problem doesn't exist in any other leap year, or year ending with "00". It is the only test I am failing, and for the life of me I can't seem to figure out what the problem is.
Here is the code:
//**********************************************************************
#include <iostream>
#include <iomanip>
using namespace std;
int getYear();
int getMonth();
int computeNumDays(int month, int year);
int computeOffset(int month, int year);
bool isLeapYear(int year);
void displayHeading(int month, int year);
void displayTable(int offset, int numDays);
/********************
* MAIN
*********************/
int main()
{
int month = getMonth();
int year = getYear();
int offset = computeOffset(month, year);
int numDays = computeNumDays(month, year);
displayHeading(month, year);
displayTable(offset, numDays);
return 0;
}
/********************
*GETMONTH
*Prompts the user for a month number
*********************/
int getMonth()
{
int month;
//Month number must be between 1 and 12
cout << "Enter a month number: ";
cin >> month;
//Displays an error message if the month is under 1 or over 12
while (month < 1 || month > 12)
{
cout << "Month must be between 1 and 12.\n";
cout << "Enter a month number: ";
cin >> month;
}
return month;
}
/********************
*GETYEAR
* prompts the user for a year
*********************/
int getYear()
{
int year;
cout << "Enter year: ";
cin >> year;
//Displays an error message if the year is less than 1753
while (year < 1753)
{
cout << "Year must be 1753 or later.\n";
cout << "Enter year: ";
cin >> year;
}
cout << "\n";
return year;
}
/********************
*COMPUTENUMDAYS
* For computing the number of days in a month, so we know where to count to when filling in
* the calendar
*********************/
int computeNumDays(int month, int year)
{
int numDays;
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return numDays = 31;
else if (month == 4 || month == 6 || month == 9 || month == 11)
return numDays = 30;
else if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
return numDays = 29;
else if (month == 2)
return numDays = 28;
}
/*********************
*COMPUTEOFFSET
*********************/
int computeOffset(int month, int year)
{
int totalYearDays = 0;
int totalMonthDays = 0;
//This counts up all the days between the January 1st of 1753 to January 1st of the users input
//year. Leap years are accounted for with the IF statements and the isLeapYear function
for (int yearCount = 1753; yearCount < year; yearCount++)
{
if (isLeapYear(yearCount))
totalYearDays += 366;
else
totalYearDays += 365;
}
//The days of the month of the user input year are added up here. If the user inputs February(2),
//then it counts the days of each month in between and adds them up.
for (int monthCount = 0; monthCount < month; monthCount++)
{
if (monthCount == 1 || monthCount == 3 || monthCount == 5)
totalMonthDays += 31;
else if (monthCount == 7 || monthCount == 8 || monthCount == 10 || monthCount == 12)
totalMonthDays += 31;
else if (monthCount == 4 || monthCount == 6 || monthCount == 9 || monthCount == 11)
totalMonthDays += 30;
//if the user input year is a leap year, then an extra day to February is added
else if (monthCount == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
totalMonthDays += 29;
else if (monthCount == 2)
totalMonthDays += 28;
}
int offset = (totalYearDays + totalMonthDays) % 7;
return offset;
}
/******************************************
* ISLEAPYEAR
******************************************************/
bool isLeapYear(int yearCount)
{
//Equation for determining if a year is a leap year or not
if ((yearCount % 4 == 0 && yearCount % 100 != 0) || (yearCount % 400 == 0))
return true;
else
return false;
}
/*************************************************
*DISPLAYHEADING
* This is where the Month Name and Year are shown
**************************************************/
void displayHeading(int month, int year)
{
if (month == 1)
cout << "January, " << year << endl;
else if (month == 2)
cout << "February, " << year << endl;
else if (month == 3)
cout << "March, " << year << endl;
else if (month == 4)
cout << "April, " << year << endl;
else if (month == 5)
cout << "May, " << year << endl;
else if (month == 6)
cout << "June, " << year << endl;
else if (month == 7)
cout << "July, " << year << endl;
else if (month == 8)
cout << "August, " << year << endl;
else if (month == 9)
cout << "September, " << year << endl;
else if (month == 10)
cout << "October, " << year << endl;
else if (month == 11)
cout << "November, " << year << endl;
else if (month == 12)
cout << "December, " << year << endl;
return;
}
/********************
*DISPLAYTABLE
*********************/
void displayTable(int offset, int numDays)
{
//days of the week are displayed here
cout << setw(4) << "Su" << setw(4) << "Mo" << setw(4) << "Tu"
<< setw(4) << "We" << setw(4) << "Th" << setw(4) << "Fr" << setw(4)
<< "Sa" << setw(2) << endl;
//WeekBreak counter will be used to add new lines for each week
int weekBreak = 1;
//This IF statement determines the number of days before the first of the month occurs,
// as well as sets the weekBreak counter
if (offset != 6 && offset >= 0)
do
{
cout << setw(4) << " ";
offset--;
weekBreak++;
} while (offset != -1);
//The counter loop here begins putting in the dates, all the way from the first to
//the max number of days in the month
for (int date = 1; date <= numDays; date++)
{
cout << " " << setw(2) << date;
weekBreak++; //weekBreak prevents us from putting more than
//7 dates in a single week
if (weekBreak == 8)
{
cout << "\n"; //once a week hits 7 dates(or 8 spaces), it moves on to a new week
weekBreak = 1;
}
}
//this puts an end to the calander, regardless if weekBreak limit is reached
if (weekBreak >= 2 && weekBreak <= 7)
cout << "\n";
}
It bothers me that it only seems to happen for the year 2000. I'm not sure what the cause could be, so I could really use some feedback.

To debug your code I wrote the following main function:
int main()
{
for (int year = 1753; year <= 2021; year++)
{
for (int month = 1; month <= 12; month++)
{
int offset = computeOffset(month, year);
int numDays = computeNumDays(month, year);
std::chrono::year_month_day date(std::chrono::year(year), std::chrono::month(month), std::chrono::day(1));
std::chrono::weekday day{ std::chrono::sys_days(date) };
int expectedOffset = ((day - std::chrono::Monday).count() + 7) % 7;
if (expectedOffset != offset)
{
std::cout << year << "/" << month << " expected " << expectedOffset << " actual " << offset << "\n";
}
}
}
return 0;
}
This confirms it is indeed only the year 2000 which is incorrect. This suggests its the handling of the leap year every 400 years which is incorrect.
As you have a function for calculating leap years the first thing to try is to use that rather than implementing the same code three times (implementing something 3 times triples the chances of creating a bug). Changing computeNumDays to:
else if (month == 2 && isLeapYear(year))
return numDays = 29;
and computeOffset to:
else if (monthCount == 2 && isLeapYear(year))
totalMonthDays += 29;
fixes the bug.
The cause of the bug is actually the combination of 2 bugs:
in computeOffset monthCount starts from 0 not 1.
the expression monthCount == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) will always be true when year % 400 == 0 is true. The intended expression was monthCount == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
This causes the value of totalMonthDays to be 29 more than it should be for years divisible by 400, after %7 this causes the result of computeOffset to be 1 higher than it should be.
By removing repetition your code can be greatly simplified:
int computeNumDays(int month, int year)
{
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
return isLeapYear(year) ? 29 : 28;
default:
throw std::invalid_argument("invalid month");
}
}
int computeOffset(int month, int year)
{
int totalYearDays = 0;
int totalMonthDays = 0;
//This counts up all the days between the January 1st of 1753 to January 1st of the users input
//year. Leap years are accounted for with the IF statements and the isLeapYear function
for (int yearCount = 1753; yearCount < year; yearCount++)
{
if (isLeapYear(yearCount))
totalYearDays += 366;
else
totalYearDays += 365;
}
//The days of the month of the user input year are added up here. If the user inputs February(2),
//then it counts the days of each month in between and adds them up.
for (int monthCount = 1; monthCount < month; monthCount++)
{
totalMonthDays += computeNumDays(monthCount, year);
}
int offset = (totalYearDays + totalMonthDays) % 7;
return offset;
}
bool isLeapYear(int yearCount)
{
//Equation for determining if a year is a leap year or not
if ((yearCount % 4 == 0 && yearCount % 100 != 0) || (yearCount % 400 == 0))
return true;
else
return false;
}

Related

Why are my If else statements not working?

This program asks for a number from 1 to 12 and prints out the month and season correspondent to the input number, if the user types anything else than numbers from 1 to 12 an error message is displayed. It looks like the first if statement runs perfectly with its correspondent nested statements but the next else if statements wont work, try with 1, 2, and 12 and the program will work perfectly, but it doesn't with any other value, does anyone knows why this is happening?
Here's the program...
#include <iostream>
#include <string>
using namespace std;
int main() {
int number;
string season, month;
cout << "Welcome! This program will provide the season of the year based on the month you enter, 1 corresponding to January, 2 for February and so on until 12 for December" << endl << endl;
cout << "Enter a number between 1 and 12: ";
cin >> number;
if (number == 1 || 2 || 12)
{
if (number == 1)
{
month = "January";
season = "winter";
}
else if (number == 2)
{
month = "February";
season = "winter";
}
else if (number == 12)
{
month = "December";
season = "winter";
}
}
else if (number == 3 || 4 || 5)
{
if (number == 3)
{
month = "March";
season = "spring";
}
else if (number == 4)
{
month = "April";
season = "spring";
}
else if (number == 5)
{
month = "May";
season = "spring";
}
}
else if (number == 6 || 7 || 8 )
{
if (number == 6)
{
month = "June";
season = "summer";
}
else if (number == 7)
{
month = "July";
season = "summer";
}
else if (number == 8)
{
month = "August";
season = "summer";
}
}
else if (number == 9 || 10 || 11)
{
if (number == 9)
{
month = "September";
season = "fall";
}
else if (number == 10)
{
month = "October";
season = "fall";
}
else if (number == 11)
{
month = "November";
season = "fall";
}
}
else
{
cout << "You entered an ivalid value";
return 0;
}
cout << "-------------------------------------------------------------" << endl;
cout << "You entered " << number << ". " << month << " is the " << season << " season.";
return 0;
}
I believe that the || operator does not work how you are using it. That is, the statement if (number == 1 || 2 || 12) is likely being converted into boolean values:
number == 1
2
12
So imaging you are forcing each of those values into a boolean representation. There's probably a more exact way of explaining this though.
The fix is likely to do this:
if (number == 1 || number == 2 || number == 12)
etc.

Why is my code adding 93 days to the output?

I have a c++ assignment that asks to enter one date and second date and find the number of days between the two, including leap years. My code displays the correct values for two dates, however when tested for 1/2/3 to 3/21/12345, it displays 4507994, which is 93 more days than the correct value of 4507901. Why is this happening? I am including cstdlib and iostream
using namespace std;
bool isLeapYear (int year)
{
bool tf;
if (year%4 !=0)
{
tf = true;
}
else if (year%4 == 0)
{
if (year%1000 == 0)
{
if (year %400 == 0)
{
tf = false;
}
else
{
tf = true;
}
}
tf = false;
}
return tf;
}
int last_day(int month, int year)
{
int lday;
if (month == 2)
{
if (isLeapYear (year) == false)
{
lday = 29;
}
else
{
lday = 28;
}
}
else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8|| month == 10 || month ==12)
{
lday = 31;
}
else if (month == 4 || month == 6 || month == 9 || month == 11)
{
lday = 30;
}
return lday;
}
void howlongwait (int &month, int &day, int &year)
{
if (day == last_day(month, year))
{
if (month == 12 && day == 31)
{
month = 1;
day = 1;
year = year+1;
}
else
{
month = month+1;
day = 1;
year = year;
}
}
else
{
month = month;
day = day+1;
year = year;
}
}
int main()
{
int month, month2, day2, day, year, year2;
int days = 0;
char trash, garb, garb2, trash2;
cout << "Enter start date (no spaces): " << endl;
cin >> month >> trash >> day >> garb >> year;
cout << "Enter end date (no spaces): " << endl;
cin >> month2 >> trash2 >> day2 >> garb2 >> year2;
if (year2 < year)
{
cout << "Never..." << endl;
return 0;
}
else
{
while ((month != month2) || (day != day2) || (year != year2))
{
howlongwait (month, day, year);
days=days+1;
}
}
cout << "You have to wait " << days << " days" << endl;
}
`
isLeapYear should be fixed like this:
bool isLeapYear (int y)
{
return y%4 == 0 && (y%400 == 0 || y%100 != 0);
}
and please replace isLeapYear (year) == false to isLeapYear (year) == true.
Your version of isLeapYear is:
year%1000 == 0 should be year%100 == 0
corresponding else is missing
flip true and false, or change the function name if you need

Finding specific days in a specific years and leap years

so, I have this much of the program done I still have to determine what day of the week january 1st is in the current year as well as leap years: A leap year is one whose number is exactly divisible by four. Century years, however, are only leap years if they are exactly divisible by 400. Hence 1900 was not a leap year but 2000 was. Im a bit stuck on where to go from here, I understand it in my head but am having trouble putting my thoughts into code. If anyone can push me in the right direction or if you have a solution id really appreciate the help.
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
tm dateTime;
time_t systemTime = time(0);
localtime_s( &dateTime, &systemTime );
int day = dateTime.tm_mday;//theTime.tm_mday;
int month = dateTime.tm_mon+1;//theTime.tm_mon;
int year = dateTime.tm_year + 1900;//theTime.tm_year + 1900;
int weekDay = dateTime.tm_wday;
cout << "Today is ";
switch (weekDay){
case 0: cout << "Sunday, ";
break;
case 1: cout << "Monday, ";
break;
case 2: cout << "Tuesday, ";
break;
case 3: cout << "Wednesday, ";
break;
case 4: cout << "Thursday, ";
break;
case 5: cout << "Friday, ";
break;
case 6: cout << "Saturday, ";
break;
}
cout << month << "/" << day << "/" << year << endl;
}
Use modulo arithmetic operator (%) to determine if the year is dividable by 4.
If it's not, then it's not leap.
Note that a result of operator% equals 0 if and only if lhs is dividable by rhs.
Then, apply the same operator with logic that stands behind alghoritm that determines if year is leap, as you described in your question. Details are in comments of my answer's code.
[[nodiscard]]
constexpr bool IsLeap(const int & Year) noexcept
{
// If $Year is not dividable by 4, it's not leap, eg 2003.
// Otherwise, apply more logic below (for years like 2004, 2000 or 1900).
if (Year % 4 != 0) [[likely]]
return false;
// If $Year is dividable by 100, eg 2000, check if it's also dividable by 400.
// If it's also dividable by 400, it's leap, eg 2000.
// Otherwise, it's not leap, eg 1900.
if (Year % 100 == 0) [[unlikely]]
{
if (Year % 400 == 0) [[unlikely]]
return true;
return false;
}
// $Year is dividable by 4 and not by 100, so it's leap.
return true;
}
Example:
#include <iostream>
int main()
{
std::cout << std::boolalpha << IsLeap(2003) << std::endl; // false (not dividable by 4)
std::cout << std::boolalpha << IsLeap(2004) << std::endl; // true (dividable by 4 and not dividable by 100)
std::cout << std::boolalpha << IsLeap(2000) << std::endl; // true (dividable by 4, 100 and 400)
std::cout << std::boolalpha << IsLeap(1900) << std::endl; // false (dividable by 4 and 100, but not by 400)
}
To check if a given number is divisible by another number, you use the modulus (%) operator. If a % b == 0, that means that a is divisible by b.
bool is_leap_year(int year) {
if (year % 4 != 0) return false;
// Year is divisible by 4; It is a leap year
if (year % 100 == 0) {
// Unless it is also divisible by 100, in which case it is not a leap year
// Except when it is divisible by 400
if (year % 400 == 0) return true;
return false;
}
return true;
}
// Equivalent to
bool is_leap_year(int year) {
return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
}
And then when finding out what weekday it was on January 1st from the current day, you will have to use the modulus operator again. This time, you will use a % 7, which will give the remainder when something is divided by 7 (So 15 days ago is 15 % 7 == 1 day ago in a different week).
Using the epoch as a reference date (we could really pick any date), we just count up to the current date to get the day of the week.
One optimization is that we can increment the years first and just let the dayOfTheWeek variable increment by 1 or 2 depending if we're currently counting on a leap year or not.
bool isLeapYear(int year)
{
if ((year % 400) == 0)
return true;
if ((year % 100) == 0)
return false;
return ((year % 4) == 0);
}
// return the day of the week for a given month/day/year value
// Sunday is 0. Monday is 1.... Saturday is 6;
int GetDayOfWeek(int month, int day, int year)
{
int dayOfWeek = 5; // January 1, 1970 was a Thursday
int daysOfMonth = [0,31,28,31,30,31,30,31,31,30,31,30,31];
int d = 1;
int m = 1;
int y = 1970;
if (year < 1970)
return -1;
// go "year by year" incrementing dayOfWeek by 1 or 2 based on leap year
while (y < year)
{
dayOfWeek = (isLeapYear(y) ? 2 : 1) % 7;
y++;
}
while (d != day && m != month)
{
// increment the day
d++;
dayOfWeek = (dayOfWeek + 1) % 7;
if (d > daysOfMonth[m]) // new month
{
d = 1;
m++;
}
}
return dayOfWeek;
}

How can we transform a string in integer without stoi command / to input date and output integers

#include <iostream>
using namespace std;
int daysMonth (int month) // the part to clarify
{
if (month >= 1 && month <= 12){
if (month == 2)
return 28;
if (month == 4 || month == 6 || month == 9 || month == 11)
return 30;
return 31;
}
return 0;
}
void nextDay (int day, int month, int year) // nextday conditions
{
int daysOfMonth = daysMonth(month);
if ((year % 4 == 0) && (year % 100 != 0) || year % 400 == 0)
{
if (day == 28){
day = 29;
month = month;
year = year;
}
}
if (day != daysOfMonth)
{
day = day + 1;
month = month;
year = year;
}
if (day == daysOfMonth)
{
day = 1;
month = month + 1;
year = year;
}
if ((month == 12) && (day == 31))
{
day = 1;
month = 1;
year = year + 1;
}
cout << "Next day is : " << day << "/" << month << "/" << year << endl;
}
int main(){
int day;
int month;
int year;
cout << "Enter a date : " << endl;
cin >> day;
cin >> month;
cin >> year;
cout << "Your chosen date is : " << day << "/" << month << "/" << year << endl;
if (day >= 1 && day <= 31 && month >= 1 && month <= 12)
{
nextDay(day, month, year);
}
else
cout << "Invalid date" << endl;
}
Now my question is the following :
If I'm entering 28/02/2016 I'm getting 30/02/2016.
The other question is :
Is there a way to get the date in the DD/MM/YYYY format and then get the DD MM YYYY with a coommand like stoi - I mention that the command is not working for me.
I was trying to get the results like usual if I input 28/02/2016 I should get 29/02/2016 - I know there's another condition to increase the day + 1 but why isn't that skipped ?

C++ Store How many days ago a date was in a Date object

I am trying to store how many days ago a day is into an object in C++. The book says it's doing this way because C++ doesn't have a proper definition for date, or at least one that doesn't track days after 1970. I've been trying to follow a book in my leisure. The script starts off with taking three inputs, month, day, and year. It puts them through a constructor that adds a forth parameter, old, which defaults to 0.
After that my main program attempts to run a function to calculate how many days ago that day was using a pastDays function, part of a personally written Date class, and attempts to assign it to the forth parameter of old in an object.
Here we have the main.cpp / driver program. The constructor works and it creates objects of type Date.
#include <iostream>
#include "Date.h" // Date class definition
#include <time.h>
#include <ctime>
using namespace std;
int main() {
int birthMonth = 0;
int birthDay = 0;
int birthYear = 0;
int dateToMonth = 0;
int dateToDay = 0;
int dateToYear = 0;
cout << "Enter birth month (1-12): ";
cin >> birthMonth;
cout << "Enter birth day (1-31): ";
cin >> birthDay;
cout << "Enter birth year (1900 - 2000): ";
cin >> birthYear;
Date birthDate (birthMonth, birthDay, birthYear);
cout << "To which date would you like to calculate to?\nEnter Day month (1-12): ";
cin >> dateToMonth;
cout << "Enter Day to calculate it to (1-31): ";
cin >> dateToDay;
cout << "Enter Year to calculate it to: ";
cin >> dateToYear;
Date dateTo (dateToMonth, dateToDay, dateToYear);
Date d1( 12, 27, 2010, 0 ); // December 27, 2010
Date d2; // defaults to January 1, 1900
Date::pastDays(birthDate);
Date::pastDays(dateTo);
// birthDate = birthDate - dateTo;
cout << birthDate.old;
}
When I attempt to use this, on...
Date::pastDays(birthDate);
I get the error, "Cannot call member function 'int Date::pastDays(Date)' without object."
I seem to be passing the object through there.
Here is the Date.h header.
#ifndef DATE_H
#define DATE_H
#include <array>
#include <iostream>
class Date
{
friend std::ostream &operator<<( std::ostream &, const Date & );
public:
Date( int m = 1, int d = 1, int y = 1900, int o = 0 ); // default constructor
void setDate( int, int, int, int ); // set month, day, year
Date &operator++(); // prefix increment operator
Date operator++( int ); // postfix increment operator
Date &operator+=( unsigned int ); // add days, modify object
int pastDays (Date);
static bool leapYear( int ); // is date in a leap year?
bool endOfMonth( int ) const; // is date at the end of month?
unsigned int month;
unsigned int day;
unsigned int year;
int old;
static const std::array< unsigned int, 13 > days; // days per month
void helpIncrement(); // utility function for incrementing date
}; // end class Date
#endif
Here we have the main Date.cpp program. It starts by creating variables made to copy what the input day, month, and year are. I tried designing it so that pastDays takes that information, it decrements the day and month to Jan 1st, and stores it in the variable of daysAgo, the amount of negative days created.
Then it increments the year, and adds 365 or 366 depending on if it is a leap year or not. Then it increments the current day and month back up to the current day, adding the the changes back to the daysAgo variable. Then it tries to put that as the entryDay information, but in the old parameter, so that the original object now has that information filled out. At least that is the plan.
#include <iostream>
#include <string>
#include "Date.h"
#include <time.h>
#include <ctime>
#include <conio.h>
using namespace std;
// initialize static member; one classwide copy
const array< unsigned int, 13 > Date::days = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// Date constructor
Date::Date( int month, int day, int year, int old )
{
setDate( month, day, year, old );
} // end Date constructor
// set month, day and year
void Date::setDate( int mm, int dd, int yy, int old )
{
if ( mm >= 1 && mm <= 12 )
month = mm;
else
throw invalid_argument( "Month must be 1-12" );
if ( yy >= 1900 && yy <= 2100 )
year = yy;
// test for a leap year
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12){
if (dd >= 1 || dd <= 31)
day == dd;
}
if (month == 4 || month == 6 || month == 9 || month == 11){
if (dd >= 1 || dd <= 30)
day == dd;
}
if (month == 2)
if ( year % 4 != 0 ) {
if (dd >= 1 || dd <= 29)
day == dd;
}
if (month == 2)
if ( year % 4 != 0 ) {
if (dd >= 1 || dd <= 28)
day == dd;
}
else {
throw invalid_argument(
"Day is out of range for current month and year" );
}
} // end function setDate
// overloaded prefix increment operator
Date &Date::operator++()
{
helpIncrement(); // increment date
return *this; // reference return to create an lvalue
} // end function operator++
// overloaded postfix increment operator; note that the
// dummy integer parameter does not have a parameter name
Date Date::operator++( int )
{
Date temp = *this; // hold current state of object
helpIncrement();
// return unincremented, saved, temporary object
return temp; // value return; not a reference return
} // end function operator++
// add specified number of days to date
Date &Date::operator+=( unsigned int additionalDays )
{
for ( int i = 0; i < additionalDays; ++i )
helpIncrement();
return *this; // enables cascading
} // end function operator+=
Date pastDays (Date &entryDay) {
//Creating Today date object
time_t t = time(0);
struct tm * now = localtime(&t);
int currentYear = now -> tm_year + 1900;
int currentMonth = now -> tm_mon + 1;
int currentDay = now -> tm_mday;
int birthMonth = entryDay.month;
int birthDay = entryDay.day;
int birthYear = entryDay.year;
//The variable that will be assigned to the old parameter, which can then be subtracted from another time.
int daysAgo = 0;
//Lowering days to 1, to make transition between years easier.
while (birthDay > 1){
birthDay--;
daysAgo--;
}
cout << daysAgo;
//Lowering months to 1, to make transition between years easier.
while (birthMonth > 1){
if (birthMonth == 1 || birthMonth == 3 || birthMonth == 5 || birthMonth == 7 || birthMonth == 8 || birthMonth == 10 || birthMonth == 12){
birthMonth--;
daysAgo -= 31;
}
if (birthMonth == 4 || birthMonth == 6 || birthMonth == 9 || birthMonth == 11){
birthMonth--;
daysAgo -= 30;
}
if (birthMonth == 2)
if ( currentYear % 400 == 0 ||
( currentYear % 100 != 0 && currentYear % 4 == 0 ) ) {
birthMonth--;
daysAgo -= 29;
}
else {
birthMonth--;
daysAgo -= 28;
}
}
cout << daysAgo;
//Incrementing year to current year
while (birthYear < currentYear){
if ( currentYear % 400 == 0 ||
( currentYear % 100 != 0 && currentYear % 4 == 0 ) ) {
daysAgo = daysAgo + 366;
birthYear++;
}
else {
daysAgo = daysAgo + 365;
birthYear++;
}
}
cout << daysAgo;
// Incrementing to current month
while (birthMonth < currentMonth) {
if (birthMonth == 1 || birthMonth == 3 || birthMonth == 5 || birthMonth == 7 || birthMonth == 8 || birthMonth == 10 || birthMonth == 12){
birthMonth++;
daysAgo += 31;
}
if (birthMonth == 4 || birthMonth == 6 || birthMonth == 9 || birthMonth == 11){
birthMonth++;
daysAgo += 30;
}
if (birthMonth == 2)
if ( currentYear % 400 == 0 ||
( currentYear % 100 != 0 && currentYear % 4 == 0 ) ) {
birthMonth++;
daysAgo += 29;
}
else {
birthMonth++;
daysAgo += 28;
}
}
cout << daysAgo;
//Incrementing to current day, and adding the days to the daysAgo
while (birthDay < currentDay){
birthDay++;
daysAgo++;
}
cout << daysAgo;
//Assigning DaysAgo to input parameter.old
entryDay.old = daysAgo;
return(entryDay);
}
// if the year is a leap year, return true; otherwise, return false
bool Date::leapYear( int testYear )
{
if ( testYear % 400 == 0 ||
( testYear % 100 != 0 && testYear % 4 == 0 ) )
return true; // a leap year
else
return false; // not a leap year
} // end function leapYear
// determine whether the day is the last day of the month
bool Date::endOfMonth( int testDay ) const
{
if ( month == 2 && leapYear( year ) )
return testDay == 29; // last day of Feb. in leap year
else
return testDay == days[ month ];
} // end function endOfMonth
// function to help increment the date
void Date::helpIncrement()
{
// day is not end of month
if ( !endOfMonth( day ) )
++day; // increment day
else
if ( month < 12 ) // day is end of month and month < 12
{
++month; // increment month
day = 1; // first day of new month
} // end if
else // last day of year
{
++year; // increment year
month = 1; // first month of new year
day = 1; // first day of new month
} // end else
} // end function helpIncrement
// overloaded output operator
ostream &operator<<( ostream &output, const Date &d )
{
static string monthName[ 13 ] = { "", "January", "February",
"March", "April", "May", "June", "July", "August",
"September", "October", "November", "December" };
output << monthName[ d.month ] << ' ' << d.day << ", " << d.year;
return output; // enables cascading
} // end function operator<<
My main issue is that I cannot calculate the days ago it was, and store it in the fourth Date parameter.
Dot
Dot
Dot
Dot
Dot
After a few more hours, I have now modified the program to calculate how many days ago it has been. I am listing it here for others to see. Perhaps it shall help others.
main.cpp
#include <iostream>
#include <time.h>
#include <ctime>
#include "Date.cpp" // Date class definition
using namespace std;
int main() {
unsigned int birthMonth = 0;
unsigned int birthDay = 0;
unsigned int birthYear = 0;
unsigned int dateToMonth = 0;
unsigned int dateToDay = 0;
unsigned int dateToYear = 0;
cout << "Enter birth month (1-12): ";
cin >> birthMonth;
cout << "Enter birth day (1-31): ";
cin >> birthDay;
cout << "Enter birth year (1900 - 2000): ";
cin >> birthYear;
Date birthDate (birthMonth, birthDay, birthYear);
cout << "To which date would you like to calculate to?\nEnter Day month (1-12): ";
cin >> dateToMonth;
cout << "Enter Day to calculate it to (1-31): ";
cin >> dateToDay;
cout << "Enter Year to calculate it to: ";
cin >> dateToYear;
Date dateTo (dateToMonth, dateToDay, dateToYear);
pastDays(birthDate);
pastDays(dateTo);
cout << "\nHow many days ago is the birth date? " << birthDate.old << endl;
cout << "How many days ago is the secondary date? " << dateTo.old << endl;
}
Here is date.h
#ifndef DATE_H
#define DATE_H
#include <array>
#include <iostream>
class Date
{
friend std::ostream &operator<<( std::ostream &, const Date & );
public:
Date( int m = 1, int d = 1, int y = 1900, int o = 0 ); // default constructor
void setDate( int, int, int, int ); // set month, day, year
// friend Date operator - (Date &ob1, Date &ob2);
Date &operator-(); // Modified Line for Assignment
Date &operator-(Date); // Modified Line for Assignment
void pastDays (Date);
static bool leapYear( int ); // is date in a leap year?
unsigned int month;
unsigned int day;
unsigned int year;
int old;
static const std::array< unsigned int, 13 > days; // days per month
}; // end class Date
#endif
Here is Date.cpp
#include <iostream>
#include <string>
#include "Date.h"
#include <time.h>
#include <ctime>
#include <conio.h>
#include "Date.h" // Date class definition
using namespace std;
// initialize static member; one classwide copy
const array< unsigned int, 13 > Date::days = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// Date constructor
Date::Date( int month, int day, int year, int old )
{
setDate( month, day, year, old );
} // end Date constructor
// set month, day and year
void Date::setDate( int mm, int dd, int yy, int old )
{
if ( mm >= 1 && mm <= 12 )
month = mm;
else
throw invalid_argument( "Month must be 1-12" );
if ( yy >= 1900 && yy <= 2100 )
year = yy;
// test for a leap year
// if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12){
// if (dd >= 1 || dd <= 31)
// day == dd;
// }
// if (month == 4 || month == 6 || month == 9 || month == 11){
// if (dd >= 1 || dd <= 30)
// day == dd;
// }
// if (month == 2)
// if ( year % 4 != 0 ) {
// if (dd >= 1 || dd <= 29)
// day == dd;
// }
// if (month == 2)
// if ( year % 4 != 0 ) {
// if (dd >= 1 || dd <= 28)
// day == dd;
// }
// else {
// throw invalid_argument(
// "Day is out of range for current month and year" );
// }
if ( ( month == 2 && leapYear( year ) && dd >= 1 && dd <= 29 ) ||
( dd >= 1 && dd <= days[ month ] ) )
day = dd;
else
throw invalid_argument(
"Day is out of range for current month and year" );
} // end function setDate
void pastDays (Date &entryDay) {
//Creating Today date object
time_t t = time(0);
struct tm * now = localtime(&t);
int currentYear = now -> tm_year + 1900;
int currentMonth = now -> tm_mon + 1;
int currentDay = now -> tm_mday;
int birthMonth = entryDay.month;
int birthDay = entryDay.day;
int birthYear = entryDay.year;
//The variable that will be assigned to the old parameter, which can then be subtracted from another time.
int daysAgo = 0;
entryDay.old = 0;
cout << endl;
cout << "First" << daysAgo << endl;
cout << "BirthMonth: " << birthMonth << endl;
cout << "BirthDay: " << birthDay << endl;
cout << "BirthYear: " << birthYear << endl;
//Lowering days to 1, to make transition between years easier.
// while (birthDay > 1){
// birthDay--;
// daysAgo--;
// }
daysAgo = daysAgo - birthDay;
daysAgo++;
birthDay = 1;
cout << endl;
cout << "Second" << daysAgo << endl;
cout << "BirthMonth: " << birthMonth << endl;
cout << "BirthDay: " << birthDay << endl;
cout << "BirthYear: " << birthYear << endl;
//Lowering months to 1, to make transition between years easier.
while (birthMonth > 1){
if (birthMonth == 1 || birthMonth == 3 || birthMonth == 5 || birthMonth == 7 || birthMonth == 8 || birthMonth == 10 || birthMonth == 12){
birthMonth--;
daysAgo -= 31;
}
if (birthMonth == 4 || birthMonth == 6 || birthMonth == 9 || birthMonth == 11){
birthMonth--;
daysAgo -= 30;
}
if (birthMonth == 2)
if ( currentYear % 400 == 0 ||
( currentYear % 100 != 0 && currentYear % 4 == 0 ) ) {
birthMonth--;
daysAgo -= 29;
}
else {
birthMonth--;
daysAgo -= 28;
}
}
cout << endl;
cout << "Third" << daysAgo << endl;
cout << "BirthMonth: " << birthMonth << endl;
cout << "BirthDay: " << birthDay << endl;
cout << "BirthYear: " << birthYear << endl;
//Incrementing year to current year
while (birthYear < currentYear){
if ( currentYear % 400 == 0 ||
( currentYear % 100 != 0 && currentYear % 4 == 0 ) ) {
daysAgo = daysAgo + 366;
birthYear++;
}
else {
daysAgo = daysAgo + 365;
birthYear++;
}
}
cout << endl;
cout << "Fourth" << daysAgo << endl;
cout << "BirthMonth: " << birthMonth << endl;
cout << "BirthDay: " << birthDay << endl;
cout << "BirthYear: " << birthYear << endl;
// Incrementing to current month
while (birthMonth < currentMonth) {
if (birthMonth == 1 || birthMonth == 3 || birthMonth == 5 || birthMonth == 7 || birthMonth == 8 || birthMonth == 10 || birthMonth == 12){
birthMonth++;
daysAgo += 31;
}
if (birthMonth == 4 || birthMonth == 6 || birthMonth == 9 || birthMonth == 11){
birthMonth++;
daysAgo += 30;
}
if (birthMonth == 2)
if ( currentYear % 400 == 0 ||
( currentYear % 100 != 0 && currentYear % 4 == 0 ) ) {
birthMonth++;
daysAgo += 29;
}
else {
birthMonth++;
daysAgo += 28;
}
}
cout << endl;
cout << "Fifth" << daysAgo << endl;
cout << "BirthMonth: " << birthMonth << endl;
cout << "BirthDay: " << birthDay << endl;
cout << "BirthYear: " << birthYear << endl;
//Incrementing to current day, and adding the days to the daysAgo
while (birthDay < currentDay){
birthDay++;
daysAgo++;
}
cout << endl;
cout << "Sixth" << daysAgo << endl;
cout << "BirthMonth: " << birthMonth << endl;
cout << "BirthDay: " << birthDay << endl;
cout << "BirthYear: " << birthYear << endl;
//Assigning DaysAgo to input parameter.old
entryDay.old = daysAgo;
}
Date operator - (Date &date1, Date &date2)
{
Date temp;
temp.old = date1.old - date2.old;
if(temp.old < 0)
{
temp.old = temp.old * -1;
}
return(temp);
}
//Date operator-(Date birthDate)
////friend Distance operator - (Date &birthDate, Date &today)
// {
//// int birthMonth = birthDate.month;
//// int birthDay = birthDate.day;
//// int birthYear = birthDate.year;
//// int birthOld = 0;
//// Date temp (birthDate.month, birthDate.day, birthDate.year, birthDate.old);
//
//// pastDays(today);
//// pastDays(birthDate);
//
//// int currentMonth = today.month;
//// int currentDay = today.day;
//// int currentYear = today.year;
//
//// int date1 = pastDays(today);
//// int date2 = pastDays(birthDate);
// Date temp (birthDate.month, birthDate.day, birthDate.year);
//
//// int month, int day, int year, int old
//// temp.month = this -> month;
//// temp.month = this -> day;
//// temp.month = this -> year;
//// Date temp = *this;
// cout << temp.old;
//
// temp.old = *this -> old - birthDate.old;
// //Here I get "Error: Invalid use of 'this' in non-member function;
//
// return(temp);
//}
bool Date::leapYear( int testYear )
{
if ( testYear % 400 == 0 ||
( testYear % 100 != 0 && testYear % 4 == 0 ) )
return true; // a leap year
else
return false; // not a leap year
} // end function leapYear
// overloaded output operator
ostream &operator<<( ostream &output, const Date &d )
{
static string monthName[ 13 ] = { "", "January", "February",
"March", "April", "May", "June", "July", "August",
"September", "October", "November", "December" };
output << monthName[ d.month ] << ' ' << d.day << ", " << d.year;
return output; // enables cascading
} // end function operator<<
The structure of pastDays() is confusing and strange.
Date::pastDays(birthDate); ---> birthDate.pastDate(birthDate) // Would compile and maybe work.
Change to
Date::pastDays(dateTo); ---> dateTo.pastDate(dateTo) // Would compile and maybe work.
However, it would be more coherent if you just changed the signature of that function to:
void pastDays (Date &entryDay);
And remove the final return entryDay statement as the value is already being passed by reference, so entryDay will be once the function is executed.
So now, in the piece of code where you invoke the function you do not use the scope operator (::) anymore:
Date::pastDays(birthDate); ---> pastDate(birthDate);compile and maybe work.
Change to
Date::pastDays(dateTo); ---> pastDate(dateTo);