Выбрать главу

  };

  Date();

  Date(int, int, int) throw(DateError);

  Date(const std::string&) throw(DateError);

  int getYear() const;

  int getMonth() const;

  int getDay() const;

  std::string toString() const;

  friend Duration duration(const Date&, const Date&);

  friend bool operator<(const Date&, const Date&);

  friend bool operator<=(const Date&, const Date&);

  friend bool operator>(const Date&, const Date&);

  friend bool operator>=(const Date&, const Date&);

  friend bool operator==(const Date&, const Date&);

  friend bool operator!=(const Date&, const Date&);

  friend std::ostream& operator<<(std::ostream&,

                   const Date&);

  friend std::istream& operator>>(std::istream&,

                                  Date&);

private:

  int year, month, day;

  int compare(const Date&) const;

  static int daysInPrevMonth(int year, int mon);

};

#endif ///:~

//: C02:Date.cpp {O}

#include "Date.h"

#include <iostream>

#include <sstream>

#include <cstdlib>

#include <string>

#include <algorithm> // for swap()

#include <ctime>

#include <cassert>

#include <iomanip>

using namespace std;

namespace {

  const int daysInMonth[][13] = {

    {0,31,28,31,30,31,30,31,31,30,31,30,31},

    {0,31,29,31,30,31,30,31,31,30,31,30,31}};

  inline bool isleap(int y) {

    return y%4 == 0 && y%100 != 0 || y%400 == 0;

  }

}

Date::Date() {

  // Get current date

  time_t tval = time(0);

  struct tm *now = localtime(&tval);

  year = now->tm_year + 1900;

  month = now->tm_mon + 1;

  day = now->tm_mday;

}

Date::Date(int yr,int mon,int dy) throw(Date::DateError) {

  if (!(1 <= mon && mon <= 12))

    throw DateError("Bad month in Date ctor");

  if (!(1 <= dy && dy <= daysInMonth[isleap(year)][mon]))

    throw DateError("Bad day in Date ctor");

  year = yr;

  month = mon;

  day = dy;

}

Date::Date(const std::string& s) throw(Date::DateError) {

  // Assume YYYYMMDD format

  if (!(s.size() == 8))

    throw DateError("Bad string in Date ctor");

  for(int n = 8; --n >= 0;)

    if (!isdigit(s[n]))

      throw DateError("Bad string in Date ctor");

  string buf = s.substr(0, 4);

  year = atoi(buf.c_str());

  buf = s.substr(4, 2);

  month = atoi(buf.c_str());

  buf = s.substr(6, 2);

  day = atoi(buf.c_str());

  if (!(1 <= month && month <= 12))

    throw DateError("Bad month in Date ctor");

if (!(1 <= day && day <=

  daysInMonth[isleap(year)][month]))

    throw DateError("Bad day in Date ctor");

}

int Date::getYear() const { return year; }

int Date::getMonth() const { return month; }

int Date::getDay() const { return day; }

string Date::toString() const {

  ostringstream os;

  os.fill('0');

  os << setw(4) << year

     << setw(2) << month

     << setw(2) << day;

  return os.str();

}

int Date::compare(const Date& d2) const {

  int result = year - d2.year;

  if (result == 0) {

    result = month - d2.month;

    if (result == 0)

      result = day - d2.day;

  }

  return result;

}

int Date::daysInPrevMonth(int year, int month) {

  if (month == 1) {

    --year;

    month = 12;

  }

  else

    --month;

  return daysInMonth[isleap(year)][month];

}

bool operator<(const Date& d1, const Date& d2) {

  return d1.compare(d2) < 0;

}

bool operator<=(const Date& d1, const Date& d2) {

  return d1 < d2 || d1 == d2;

}

bool operator>(const Date& d1, const Date& d2) {

  return !(d1 < d2) && !(d1 == d2);

}

bool operator>=(const Date& d1, const Date& d2) {

  return !(d1 < d2);

}

bool operator==(const Date& d1, const Date& d2) {

  return d1.compare(d2) == 0;

}

bool operator!=(const Date& d1, const Date& d2) {

  return !(d1 == d2);

}

Date::Duration

duration(const Date& date1, const Date& date2) {

  int y1 = date1.year;

  int y2 = date2.year;

  int m1 = date1.month;

  int m2 = date2.month;

  int d1 = date1.day;

  int d2 = date2.day;

  // Compute the compare

  int order = date1.compare(date2);

  if (order == 0)

    return Date::Duration(0,0,0);

  else if (order > 0) {

    // Make date1 precede date2 locally

    using std::swap;

    swap(y1, y2);

    swap(m1, m2);

    swap(d1, d2);

  }

  int years = y2 - y1;

  int months = m2 - m1;

  int days = d2 - d1;

  assert(years > 0 ||

     years == 0 && months > 0 ||

     years == 0 && months == 0 && days > 0);

  // Do the obvious corrections (must adjust days

  // before months!) - This is a loop in case the

  // previous month is February, and days < -28.

  int lastMonth = m2;

  int lastYear = y2;

  while (days < 0) {

    // Borrow from month

    assert(months > 0);

    days += Date::daysInPrevMonth(

      lastYear, lastMonth--);

    --months;

  }

  if (months < 0) {

    // Borrow from year

    assert(years > 0);

    months += 12;

    --years;

  }

  return Date::Duration(years, months, days);

}

ostream& operator<<(ostream& os, const Date& d) {

  char fillc = os.fill('0');

  os << setw(2) << d.getMonth() << ‘-‘

     << setw(2) << d.getDay() << ‘-‘

     << setw(4) << setfill(fillc) << d.getYear();

  return os;

}

istream& operator>>(istream& is, Date& d) {

  is >> d.month;

  char dash;

  is >> dash;

  if (dash != '-')

    is.setstate(ios::failbit);