#ifndef CHRONO_H
#define CHRONO_H
#include <string>
#include <sstream>
namespace Chrono{
class Date{
public:
enum Month{jan=1,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec};
class Bad_date{};
Date(int dd=0,Month mm=Month(0),int yy=0);
int day() const{return d;}
Month month() const{return m;}
int year() const{return y;}
std::string string_rep() const;
void char_rep(const char*) const;
Date& add_day(int);
Date& add_month(int);
Date& add_year(int);
static void set_default(int,Month,int);
private:
int d;
Month m;
int y;
static Date default_date;
};
bool leapyear(int y)
{
if(y%100!=0&&y%4==0||y%400==0)
return true;
else
return false;
}
int diff(const Date &a,const Date& b);
Date next_weekday(const Date&);
Date next_saturday(const Date&);
Date Date::default_date(22,jan,1901);
void Date::set_default(int dd,Month mm,int yy)
{
default_date.d=dd;
default_date.m=mm;
default_date.y=yy;
}
Date::Date(int dd,Month mm,int yy)
{
//数据合法性检验
if(yy==0) yy=default_date.year();
if(mm==Month(0)) mm=default_date.month();
if(dd==0) dd=default_date.day();
int max;
switch(mm){
case feb:
max=28+leapyear(yy);
break;
case apr:case jun:case sep:case nov:
max=30;
break;
case jan:case mar:case may:case jul:case aug:case oct:case dec:
max=31;
break;
default:
throw Bad_date();
}
if(dd<1||max<dd) throw Bad_date();
d=dd;
m=mm;
y=yy;
}
Date& Date::add_day(int n)
{
if(n==0) return *this;
if(n>0){
while(true){
if(n>=365+leapyear(y))
n-=365+leapyear(y);
else
break;
add_year(1);
}
int max;
while(true){
switch(m){
case feb:
max=28+leapyear(y);
break;
case apr:case jun:case sep:case nov:
max=30;
break;
case jan:case mar:case may:case jul:case aug:case oct:case dec:
max=31;
break;
}
if(n>=max)
n-=max;
else
break;
add_month(1);
}
if(d+n>max){
add_month(1);
d=d+n-max;
}
else
d=d+n;
return *this;
}
n=-n;
while(true){
if(n>=365+leapyear(y))
n-=365+leapyear(y);
else
break;
add_year(-1);
}
int max;
while(true){
switch(m){
case feb:
max=28+leapyear(y);
break;
case apr:case jun:case sep:case nov:
max=30;
break;
case jan:case mar:case may:case jul:case aug:case oct:case dec:
max=31;
break;
}
if(n>=max)
n-=max;
else
break;
add_month(-1);
}
if(d-n<=0){
add_month(-1);
switch(m){
case feb:
max=28+leapyear(y);
break;
case apr:case jun:case sep:case nov:
max=30;
break;
case jan:case mar:case may:case jul:case aug:case oct:case dec:
max=31;
break;
}
d=d-n+max;
}
else
d=d-n;
return *this;
}
Date& Date::add_month(int n)
{
if(n==0) return *this;
if(n>0){
int delta_year=n/12;
int mm=m+n%12;
if(12<mm){
++delta_year;
mm-=12;
}
int max;
switch(m){
case feb:
max=28+leapyear(y+delta_year);
break;
case apr:case jun:case sep:case nov:
max=30;
break;
case jan:case mar:case may:case jul:case aug:case oct:case dec:
max=31;
break;
}
if(d>max){
d=1;
++mm;
}
m=Month(mm);
y+=delta_year;
return *this;
}
n=-n;
int delta_year=n/12;
int mm=m-n%12;
if(mm<=0){
++delta_year;
mm+=12;
}
int max;
switch(m){
case feb:
max=28+leapyear(y+delta_year);
break;
case apr:case jun:case sep:case nov:
max=30;
break;
case jan:case mar:case may:case jul:case aug:case oct:case dec:
max=31;
break;
}
if(d>max){
d=d-max;
++mm;
}
m=Month(mm);
y-=delta_year;
return *this;
}
Date& Date::add_year(int n)
{
if(d==29&&m==feb&&leapyear(y+n)){
m=mar;
d=1;
}
y+=n;
return *this;
}
std::string Date::string_rep() const
{
std::ostringstream format_oss;
format_oss<<d<<" , "<<m<<" , "<<y<<"\n";
return format_oss.str();
}
void Date::char_rep(const char* cstr) const
{
std::ostringstream format_oss;
format_oss<<d<<" , "<<m<<" , "<<y<<"\n";
cstr=format_oss.str().c_str();
}
inline bool operator==(const Date& lhs,const Date& rhs)
{
return lhs.day()==rhs.day()&&
lhs.month()==rhs.month()&&
lhs.year()==rhs.year();
}
}
#endif