날짜 처리를 위한 Date 클래스 (Dates Manipulation)

cpp
#include <iostream>
#include <cstring>
#include <sstream> // new header including - using stringstream (Date::toString())
#include <cassert> // using assert function

using namespace std;

class Date {

 // Put your private data fields here.

 private:

 // friend member
 friend ostream& operator<<(ostream& output, Date* p)
 {
  output << p->toString(); // This mean output(Date* p's address) changes string p->toString(). 
  return output;  
 }; 
 // operator'<<' overloading .. 
 // if Date* d1 = new Date(12/31/2009); , cout << d1;'s output is  d1's address..
 // To solve this problem, I choose operator << overloading.
 // I don't add This line (friend ostream& op...) to class Date public.
 // It is private , not public. So, it is legal! (from Notes on grading)
 // operator << overloading - reference : http://www.fredosaurus.com/notes-cpp/oop-friends/overload-io.html
 
 int m_month;
 int m_day;
 int m_year;

 // Constructs a date with the given month, day and year.   If the date is
 // not valid, the entire program will halt with an error message.
 // @param month is a month, numbered in the range 1...12.
 // @param day is between 1 and the number of days in the given month.
 // @param year is the year in question, with no digits omitted.
public:
 Date(int month, int day, int year) 
 {
 
  // error message - for Invalid Date
  assert(isValidDate(month, day, year)); // print error message & line number & program halts
  
  m_month = month;
  m_day = day;
  m_year = year;

 }

 // Constructs a Date object corresponding to the given string.
 // @param s should be a string of the form "month/day/year" where month must
 // be one or two digits, day must be one or two digits, and year must be
 // between 1 and 4 digits.  If s does not match these requirements or is not
 // a valid date, the program halts with an error message.

 Date(string s) 
 {

  // Convert string to int using C++ - reference : http://www.techbytes.ca/techbyte99.html (lang:english)

 const char* ds = s.c_str(); // convert string to const char*
  int k=0,t=0;
  unsigned i=0;
  int month,day,year;
  string t_s;
  const char* t_c;


  // string 
  for(i=0;i<s.length();i++) 
  {
   if(ds[i] == '/') k++; 
  }
  
  if(k>2) 
  {
   cout << "\nError: Invalid String.\n";
  } else {

  k=0; 
  // string::length - reference : http://www.cplusplus.com/reference/string/string/length/
  for(i=0;i<s.length();i++) // s.length() means string s's length.
  {
   if(ds[i] == '/')
   { 
    k++;
    t_s = s.substr(t, i-1); // substr from string s 
    // string::substr - reference : http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
    if(t==0&&i==1) t_s=s[0];
    t_c = t_s.c_str(); // string member - c_str() .. convert string to const char*
    if(k==1) { // first-order - t_c is 'const char*' & it means month
     
     month = atoi(t_c);t=i+1; // function atoi(const char*) - convert const char* to integer
    }

    if(k==2) { // second-order - t_c is 'const char*' & it means day
     day = atoi(t_c);t=i+1; 
    }

   }


   if(i==s.length()-1) { // t_c means year
    t_s = s.substr(t, i-1);
    t_c = t_s.c_str();
    year = atoi(t_c); //break; 
   }


  }
  
  
  // error message - for Invalid Date
  assert(isValidDate(month, day, year)); // print error message & line number & program halts
   
  m_month = month;
  m_day = day;
  m_year = year;

  }
 }

 // Checks whether the given year is a leap year.
 // @return true if and only if the input year is a leap year.

 static bool isLeapYear(int year) 
 {

  // leapyear reference : http://blog.naver.com/makesome/140002664401 (lang:korean)

  if(year%4==0)
  { 
   if(year>=1582) 
   { 
    if(year%100==0)
    {
     if(year%400 ==0)
     {
      return true;
     } else {
      return false;
     }
    } else {
     return true;
    }
   } else {
    return true;
   }
  } else {
   return false;
  }                       // replace this line with your solution
 }

 // Returns the number of days in a given month.
 // @param month is a month, numbered in the range 1...12.
 // @param year is the year in question, with no digits omitted.
 // @return the number of days in the given month.

 static int daysInMonth(int month, int year) 
 {
  
  if(month==1 ||month==3 ||month==5 ||month==7 ||month==8 ||month==10 ||month==12) 
  { 
   return 31;
  } else if(month==2) {
   if(isLeapYear(year)) 
   {
    return 29;
   } else {
    return 28;
   }
  } else { 
   return 30;
  }
  
 }

 // Checks whether the given date is valid.
 // @return true if and only if month/day/year constitute a valid date.
 // Years prior to A.D. 1 are NOT valid.

 static bool isValidDate(int month, int day, int year) 
 {

  if(year < 1 || year>9999) return false; // Years prior to A.D. 1 are NOT valid.
  if(month < 1 || month >12) return false;
  if(day<1 || day>daysInMonth(month,year)) return false;

  return true;

 }

 // Returns a string representation of this date in the form month/day/year.
 // The month, day, and year are printed in full as integers; for example,
 // 12/7/2006 or 3/21/407.
 // @return a string representation of this date.

 string toString() 
 {


  // old C style (failed) - using non-standard function: itoa, _itoa, _itoa_s (only for microsoft visual studio)
  /*
  char buffer[4];
  _itoa_s(m_month, buffer, 10);
  string month = buffer;
  _itoa_s(m_day, buffer, 10);
  string day = buffer;
  _itoa_s(m_year, buffer, 10);
  string year = buffer;
  */

  // New C++ Style - using stringstream
  //
  // standard string class - reference : http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html (lang:english)
  //
  // C++ string class - reference : http://www.synch3d.com/wiki/moin/moin.cgi/C_2b_2b_20string_20_c5_ac_b7_a1_bd_ba (lang:korean)
  //
  // How do I convert a value (a number, for example) to a std::string?
  // - reference : http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.1
  //
  // C++ — Convert int to string
  // - reference : http://notfaq.wordpress.com/2006/08/30/c-convert-int-to-string/

  string is;
  stringstream s_month,s_day,s_year;
  s_month << m_month;
  is += s_month.str();
  is += '/';
  s_day << m_day;
  is += s_day.str();
  is += '/';
  s_year << m_year;
  is += s_year.str();

  return is;                     
 }

 // Determines whether this Date is before the Date d.
 // @return true if and only if this Date is before d. 

 bool isBefore(Date* d) 
 {
  
  if(m_year < d->m_year)
  {
   return true;
  } else if(m_year > d->m_year) 
  {
   return false;
  } else {
     if(m_month < d->m_month)
   {
    return true;
   } else if(m_month > d->m_month) 
   {
    return false;
   } else { 
      if(m_day < d->m_day)
    {
     return true;
    } else {
     return false;
      }
   }
  }
  
     
 }

 // Determines whether this Date is after the Date d.
 // @return true if and only if this Date is after d. 

 bool isAfter(Date* d) 
 {
  if(m_year > d->m_year)
  {
   return true;
  } else if(m_year < d->m_year) 
  {
   return false;
  } else {
     if(m_month > d->m_month)
   {
    return true;
   } else if(m_month < d->m_month) 
   {
    return false;
   } else { 
      if(m_day > d->m_day)
    {
     return true;
    } else {
     return false;
      }
   }
  }                       
 }

 // Returns the number of this Date in the year.
 // @return a number n in the range 1...366, inclusive, such that this Date
 // is the nth day of its year.  (366 is only used for December 31 in a leap
 // year.)
  
 int dayInYear() 
 {


  int tmp, sum=0, t_month;
  
  for (t_month=1;t_month<m_month;t_month++)
  {

  tmp = daysInMonth(t_month,m_year);

  sum += tmp;
  
  }

  sum += m_day;

  return sum;

 }

 // Determines the difference in days between d and this Date.  For example,
 // if this Date is 12/15/1997 and d is 12/14/1997, the difference is 1.
 // If this Date occurs before d, the result is negative.
 // @return the difference in days between d and this date.

 int difference(Date* d)
 {

  int i, sum=0, c_year;

  if(isAfter(d))
  {
   c_year = m_year - d->m_year;
   if(c_year==0) 
   {
    return (dayInYear()-d->dayInYear());
   } else  {
    
    for(i=d->m_year;i<m_year;i++)
    {
     if(isLeapYear(i)) sum+=366;
     else sum+=365;
    }
    
    
    sum += dayInYear() - d->dayInYear();

    return sum;
   }

  } else if(isBefore(d)) {
   
   c_year = d->m_year - m_year;
   if(c_year==0)
   {
    return (dayInYear()-d->dayInYear());
   } else {

    for(i=m_year;i<d->m_year;i++)
    {
     if(isLeapYear(i)) sum+=366;
     else sum+=365;
    }
    
    
    sum += d->dayInYear() - dayInYear();

    return (-sum);

   }
  } else {
   
   return 0;

  }
  
  
 }

};

int main() 
{

 cout << "\nTesting constructors." << endl;
 Date* d1 = new Date(1, 1, 1);


 /*
 // Test Temp value
 string temp_string;unsigned int i;
 // Testing Date.toString()
 temp_string = d1->toString();
 cout << "\nTesting Date class by three integer- \nDate should be 1/1/1: ";
 for(i=0;i<temp_string.length();i++) cout << temp_string[i];
 cout << "\n\n";
 // end
 */


 cout << "Date should be 1/1/1: " << d1 << endl;
 d1 = new Date("2/4/2");
 cout << "Date should be 2/4/2: " << d1 << endl;
 d1 = new Date("2/29/2000");
 cout << "Date should be 2/29/2000: " << d1 << endl;
 d1 = new Date("2/29/1904");
 cout << "Date should be 2/29/1904: " << d1 << endl;

 /*
 // Testing Date.toString()
 temp_string = d1->toString();
 cout << "\nTesting Date class by string- \nDate should be 2/29/1904: ";
 for(i=0;i<temp_string.length();i++) cout << temp_string[i];
 cout << "\n\n";
 // end
 */

 d1 = new Date(12, 31, 1975);
 cout << "Date should be 12/31/1975: " << d1 << endl;
 Date* d2 = new Date("1/1/1976");
 cout << "Date should be 1/1/1976: " << d2 << endl;
 Date* d3 = new Date("1/2/1976");
 cout << "Date should be 1/2/1976: " << d3 << endl;

 Date* d4 = new Date("2/27/1977");
 Date* d5 = new Date("8/31/2110");

 // I recommend you write code to test the isLeapYear function!
 cout << "\nTesting isLeapYear(int year)- \noutput should be 1-0-1-1: ";
 cout<< d1->isLeapYear(1996) << "-" << d1->isLeapYear(1900) << "-" << d1->isLeapYear(2000) << "-" << d1->isLeapYear(1000) << endl; 
 // output : 1-0-1-1
 //cout << d1->toString();
 // end

 cout << "\nTesting before and after." << endl;
 cout << d2 << " after " << d1 << " should be true: " << d2->isAfter(d1) << endl;
 cout << d3 << " after " << d2 << " should be true: " << d3->isAfter(d2) << endl;
 cout << d1 << " after " << d1 << " should be false: " << d1->isAfter(d1) << endl;
 cout << d1 << " after " << d2 << " should be false: " << d1->isAfter(d2) << endl;
 cout << d2 << " after " << d3 << " should be false: " << d2->isAfter(d3) << endl;

 cout << d1 << " before " << d2 << " should be true: " << d1->isBefore(d2) << endl;
 cout << d2 << " before " << d3 << " should be true: " << d2->isBefore(d3) << endl;
 cout << d1 << " before " << d1 << " should be false: " << d1->isBefore(d1) << endl;
 cout << d2 << " before " << d1 << " should be false: " << d2->isBefore(d1) << endl;
 cout << d3 << " before " << d2 << " should be false: " << d3->isBefore(d2) << endl;

 cout << "\nTesting difference." << endl;
 cout << d1 << " - " << d1 << " should be 0: " << d1->difference(d1) << endl;
 cout << d2 << " - " << d1 << " should be 1: " << d2->difference(d1) << endl;
 cout << d3 << " - " << d1 << " should be 2: " << d3->difference(d1) << endl;
 cout << d3 << " - " << d4 << " should be -422: " << d3->difference(d4) << endl;
 cout << d5 << " - " << d4 << " should be 48762: " << d5->difference(d4) << endl;

}