http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h
Chapter 9 // Exercise 12
Change the representation of a Date to be the number of days since January 1, 1970 (known as day 0), represented as a long int, and re-implement the functions from section 9.8. Be sure to reject dates outside the range we can represent that was (feel free to reject days before day 0, i.e no negative days).
dateclass.h
dateclass.cpp
dateclass.h
//dateclass.h #ifndef _DATECLASS_H_ #define _DATECLASS_H_ #include "std_lib_facilities.h" enum class Month { jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec }; enum class Day { monday = 1, tuesday, wednesday, thursday, friday, saturday, sunday }; //forward declaration Month returnMonth(int month); Day returnDay(int day); //9.8 The Date Class class Date { public: Date(); ~Date(); Date(int y, Month m, int d); //check for valid date & initialise //non-modifying operations: int day() const { return d; }; Month month() const { return m; } int year() const { return y; } //modifying operations: void add_day(int n); void add_month(int n); void add_year(int n); private: int y; Month m; int d; bool lastDay = false; bool endYear = false; }; //helper functions bool is_date(int y, Month m, int d); //true for valid date bool leapyear(int y); //true if y is leap year Day findDayOfWeek(const Date& d); //returns the day for the given date Day next_workday(const Date& d); //retrieves the next work day int week_of_the_year(const Date& d); //returns the number of the week in the year int howManyDaysSince(const Date& d); //returns how many days since the start of the year long int daysSince(const Date& date1, const Date& date2); //returns how many days between two given dates
void printDay(const Day& day); //prints out day in written form ostream& operator<<(ostream& os, Date& d); istream& operator>>(istream& is, Date& dd); bool operator==(const Date& a, const Date& b); bool operator!=(const Date& a, const Date& b); //to help with finding day for any given date struct stringInt { int monthDay; int key; }; #endif // !_DATECLASS_H_
dateclass.cpp
//dateclass.cpp #include "dateclass.h" vector<stringInt> monthKey { { 3, 1 },{ 4, 2 },{ 5, 3 },{ 6, 4 },{ 7, 5 },{ 8, 6 },{ 9, 7 },{ 10, 8 },{ 11, 9 },{ 12, 10 },{ 1, 11 },{ 2, 12 } }; vector<stringInt> dayKey { { 7, 0 },{ 1, 1 },{ 2, 2 },{ 3, 3 },{ 4, 4 },{ 5, 5 },{ 6, 6 } }; //default Date Constructor Date::Date() { y = 2001; m = Month::jan; d = 1; } //deconstructor Date::~Date() {} //Date Constructor - initialise the day Date::Date(int y, Month m, int d) { //check that y m d is a valid date if (!is_date(y, m, d)) cout << "Error, invalid date." << endl; else { //if date is valid, initalise the date Date::y = y; Date::m = m; Date::d = d; } return; } //increment date by n days void Date::add_day(int n) { //if day goes above 31, increase month, set day to 1 //if month goes above 12, increase year, set month to 1 for (int i = 0; i < n; ++i) { //wrap days if (Date::d == 31) lastDay = true; Date::d = (Date::d == 31) ? 1 : ++Date::d; //if day is equal to 31, make it 1, otherwise ++ if (lastDay) { //wrap month lastDay = false; int mon = (static_cast<int>(Date::m) == 12) ? 1 : (static_cast<int>(Date::m) + 1); //if month is equal to 12, make it 1, otherwise ++ Date::m = returnMonth(mon); if (static_cast<int>(Date::m) == 12) endYear = true; if (endYear) { //just increase year by one endYear = false; ++Date::y; } } } } void Date::add_month(int n) { for (int i = 0; i < n; ++i) { //if month is equal to 12, make it 1, otherwise ++ int mon = (static_cast<int>(Date::m) == 12) ? 1 : (static_cast<int>(Date::m) + 1); Date::m = returnMonth(mon); if (static_cast<int>(Date::m) == 12) endYear = true; if (endYear) { //just increase year by one endYear = false; ++Date::y; } } } void Date::add_year(int n) { for (int i = 0; i < n; ++i) ++Date::y; } //switch to return correct type of Month Month returnMonth(int month) { switch (month) { case 1: return Month::jan; break; case 2: return Month::feb; break; case 3: return Month::mar; break; case 4: return Month::apr; break; case 5: return Month::may; break; case 6: return Month::jun; break; case 7: return Month::jul; break; case 8: return Month::aug; break; case 9: return Month::sep; break; case 10: return Month::oct; break; case 11: return Month::nov; break; case 12: return Month::dec; break; default: cout << "Bad month" << endl; } } //switch to return correct day Day returnDay(int day) { switch (day) { case 7: return Day::sunday; break; case 1: return Day::monday; break; case 2: return Day::tuesday; break; case 3: return Day::wednesday; break; case 4: return Day::thursday; break; case 5: return Day::friday; break; case 6: return Day::saturday; break; default: cout << "Bad day" << endl; } } void printDay(const Day& day) { switch (day) { case Day::sunday: cout << "Sunday\n"; break; case Day::monday: cout << "Monday\n"; break; case Day::tuesday: cout << "Tuesday\n"; break; case Day::wednesday: cout << "Wednesday\n"; break; case Day::thursday: cout << "Thursday\n"; break; case Day::friday: cout << "Friday\n"; break; case Day::saturday: cout << "Saturday\n"; break; default: cout << "Bad day" << endl; } } //true for valid date bool is_date(int y, Month m, int d) { //check that y is valid if (y < 1900 || y > 2018) { cout << "Error, invalid year." << endl; return false; } //check that m is valid if (m < Month::jan || m > Month::dec) return false; //check that d is valid if (d <= 0) return false; //d must be positive int daysInMonth = 31; //most months have 31 days switch (m) { case Month::feb: //if leapyear, make it 29, if not make it 28 daysInMonth = (leapyear(y)) ? 29 : 28; break; case Month::apr: case Month::jun: case Month::sep: case Month::nov: daysInMonth = 30; //the rest have 30 days break; } if (daysInMonth < d) return false; return true; } //this was wrong in previous chapters, I've realised this now and changed it //new version of leapyear bool leapyear(int y) { //if century year, must be divisible by 400 if (y % 400 == 0) return true; //if normal year and divisible by 4 if (y % 4 == 0) return true; //else not leap year else return false; } //find day of the week for any year using Zeller's Rule Day findDayOfWeek(const Date& d) { int day, month, year, century; //get day day = d.day(); //get key for month for (int i = 0; i < monthKey.size(); ++i) { if (monthKey[i].monthDay == static_cast<int>(d.month())) month = monthKey[i].key; } //get last two digits of year year = d.year() % 100; if (month == 11 || month == 12) year -= 1; //get the century - first 2 digits of year string y = to_string(d.year()); char y1 = y.at(0); char y2 = y.at(1); string y3; y3 += y1; y3 += y2; century = stoi(y3); int f = d.day() + ((13 * month - 1) / 5) + year + (year / 4) + (century / 4) - (2 * century); day = f % 7; //get which day it is for (int i = 0; i < dayKey.size(); ++i) { if (day == dayKey[i].key) day = dayKey[i].monthDay; } return returnDay(day); } //retrieves the next work day Day next_workday(const Date& d) { //find the current day Day current = findDayOfWeek(d); //find next day Date nextDay(d); nextDay.add_day(1); Day next = findDayOfWeek(nextDay); while (next == Day::saturday || next == Day::sunday) { nextDay.add_day(1); next = findDayOfWeek(nextDay); } return next; } //returns how many days since the start of the year int howManyDaysSince(const Date& d) { int day = d.day(); int month = static_cast<int>(d.month()); cout << "Month: " << month << endl; int year = d.year(); vector<int> daysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; vector<int> daysInMonthLeap = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int result = 0; if (leapyear(year)) { for (int i = 0; i < month - 1; ++i) result += daysInMonthLeap[i]; result += day; } else { for (int i = 0; i < month - 1; ++i) result += daysInMonth[i]; result += day; } return result; } //finds out what number week of the year it is int week_of_the_year(const Date& d) { int daysSince1st = howManyDaysSince(d); //how many days have passed since jan 1st of given year? cout << "Days since 1st: " << daysSince1st << endl; int dow; //day of week. sun = 0, mon = 1 etc.. int dowJan1; //day of week on jan 1st //find out day of week for current day Day day = findDayOfWeek(d); if (day == Day::sunday) dow = 0; else dow = static_cast<int>(day); //find out day of week for jan 1st of given year day = findDayOfWeek(Date(d.year(), Month::jan, 1)); if (day == Day::sunday) dowJan1 = 0; else dowJan1 = static_cast<int>(day); //find week number int weekNum = ((daysSince1st + 6) / 7); if (dow < dowJan1) ++weekNum; return weekNum; } //compares dates bool operator==(const Date& a, const Date& b) { return a.year() == b.year() && a.month() == b.month() && a.day() == b.day(); } bool operator!=(const Date& a, const Date& b) { return !(a == b); } //print to screen ostream& operator<<(ostream& os, Date& d) { return os << d.day() << ", " << static_cast<int>(d.month()) << ", " << d.year() << endl; } //write into Date istream& operator>>(istream& is, Date& dd) { int y, m, d; char ch1, ch2, ch3, ch4; is >> ch1 >> y >> ch2 >> m >> ch3 >> d >> ch4; if (!is) return is; if (ch1 != '(' || ch2 != ',' || ch3 != ',' || ch4 != ')') { //format error is.clear(ios_base::failbit); //set the failbit return is; } dd = Date(y, Month(m), d); //update dd return is; }
//finds how many days have passed between two given dates long int daysSince(const Date& date1, const Date& date2) { long int daysSince = 0; Date tempDate = date1; //get how many years have passed between two dates int years = date2.year() - date1.year(); //add number of days to daysSince for every year for (int i = years; i >= 1; --i) { //if leap year, add 366 days if (leapyear(tempDate.year())) { daysSince += 366; } //if not leap year only add 365 else daysSince += 365; //increase tempDate so correct days are added tempDate.add_year(1); } //when we get to current year, calculate remaining days & add to total daysSince += howManyDaysSince(date2); return daysSince; }
main.cpp
//main.cpp #include "std_lib_facilities.h" #include "dateclass.h" int main() { //intialise dates Date today(2018, Month::sep, 24); Date zero(1970, Month::jan, 1); //print how many days between 2 given dates, earliest date first cout << "Days since Jan 1st 1970: " << daysSince(zero, today) << endl; keep_window_open(); return 0; }
Ohhh kay. It's been a while. I didn't realise I had completely forgotten about this book over summer...whoops. Anyway, I'm going to try and do an exercise a night from now on.
First things first, I realised that my implementation of leapyear() was completely wrong. I've now changed it and it's working properly now.
First things first, I realised that my implementation of leapyear() was completely wrong. I've now changed it and it's working properly now.
Now for the exercise, I didn't want to change the implementation of Date so instead I created a new function which takes two dates and works out how many days have passed since then. This new function is called daysSince(Date, Date). It takes two dates (no error checking just to keep code size down, so please put the earliest date first), then works out how many years are between the two. It then has a variable called daysSince which starts at 0. For every year either 365 or 366 (for leap years, checked using leapyear()) is added to it until we get to the current year. It then works out how many days since the start of the year using howManyDaysSince(Date) and adds that to the running total to get how many days between the two dates.
There are many sites on the internet which can work this out for you, however, they all seem to be out by a couple of days or even a month. I strongly believe my version is correct, if not, it is only out by one day. That I'm sure of.