模拟实现日期万年历,包括日期加减天数,日期减日期,可输出一定年份月份的日历
包括自己实现构造函数,拷贝构造函数,运算符重载等默认的成员函数
输出日历实例类似下图:
【思路分析】
要打印出日期万年历首先需要知道该年是否是闰年?是闰年该年有366天,非闰年365天;确定闰年之后还需要知道该年的每个月的总天数,在这里我用了一个数组来存储每个月的天数,是闰年就将二月修改为29天,非闰年不做修改(28天),在设置存储月份时浪费掉了下标为0的元素,更加贴近实际;有了这些基础之后下面就是如何打印日历了
在打印日期万年历时需要求出该月的第一天为星期几?在这里我提供两种思路:
想法一:
设置日期原点,我设置的日期原点是1600.1.1(周六),大家可根据自己的喜好设置日期原点,最好设置为周一方便后来计算;设置好日期原点之后我们需要计算出目标月份的第一天与原点日期相差的天数,此时就用到我们之前实现的日期减日期函数啦;求出相差天数之后我们只需要对这个相差天数加上之前日期原点的周六再一直%7直到week小于7就可以了(一周为七天),如果最后week必7大,我们只需要减7就可以处理好;在这里未处理年份小于日期原点(1600.1.1)的日期
想法二:
利用蔡勒公式,有兴趣的童鞋可以自己下去百度,在这里我就不详加介绍了
求出该月的第一天为星期几之后就是打印该日历的格式了,用双重的for循环就可以实现,详情请见代码实现部分
在这里我要穿插介绍一条关于C++中背景颜色的语句:system("color 0A")
其中color后面的0是背景色代号,A是前景色代号。各颜色代码如下:
0=黑色 1=蓝色 2=绿色 3=湖蓝色 4=红色 5=紫色 6=黄色 7=白色 8=灰色 9=淡蓝色 A=淡绿色 B=淡浅绿色 C=淡红色 D=淡紫色 E=淡黄色 F=亮白色
读者可根据自己的喜好设置背景颜色
【代码实现部分】
Date.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Date
{
friend void PrintDate(int year, int month); //友元函数
public:
Date(int year=2016,int month=1,int day=1) //初始化列表的方式
:_year(year)
,_month(month)
,_day(day)
{
if (month > 12 || day > InitDay(*this))
{
cout<<"输入日期不合法"<<endl;
}
}
Date(const Date& d)
:_year(d._year)
,_month(d._month)
,_day(d._day)
{}
Date& operator=(const Date& d);
public:
void Display()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
Date operator+(int day); //日期加减天数
Date operator-(int day);
int operator-(const Date& d); //日期减日期
bool operator==(const Date& d); //运算符重载
bool operator>(const Date& d);
bool Date::operator<(const Date& d);
private:
bool JudgeLeap(int year); //检查闰年
int InitDay(const Date& d); //计算该日期中当月的天数
private:
int _year;
int _month;
int _day;
};
void PrintDate(int year, int month); //打印日历
Date.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
Date Date::operator+(int day)
{
int tmp=0;
Date d(*this);
while(day > 0)
{
if(d._month == 13)
{
//如果是13月则直接跳入下一年
d._year++;
d._month = 1;
}
tmp=InitDay(d)-d._day; //该月剩余的天数
if(d._day+day > InitDay(*this))
{
//要加的天数大于该月剩余的天数
day -= tmp;;
d._month++;
d._day = 0;
}
else
{
//要加的天数小于该月剩余的天数
d._day += day;
day = 0;
}
}
return d;
}
Date Date::operator-(int day) //类似日期加天数
{
Date d(*this);
while(day > 0)
{
if(d._month == 0)
{
//如果是下标为0的元素直接到前一年
d._year--;
d._month = 12;
}
if(d._day-day <= 0)
{
d._month--;
day -= d._day;
d._day = InitDay(d);
}
else
{
d._day -= day;
day = 0;
}
}
return d;
}
int Date::operator-(const Date& d)
{
int day = 0; //用于统计日期之间相差的天数
Date small(d);
Date large(*this);
//large指向大日期,small指向小日期
if ((!(*this > d))) //<=
{
small = *this;
large = d;
}
while (small._year < large._year) //不同年的情况
{
if (JudgeLeap(small._year)) //是闰年
{
day += 366;
}
else
{
day += 365;
}
small._year++;
while (small._month > large._month)
{
day -= InitDay(small);
small._month--;
}
}
while (small._month < large._month) //同年不同月
{
day += InitDay(small);
small._month++;
}
day += (large._day - small._day); //同年同月直接相减天数
if ((!(*this < d))) //可能出现相减为负数的情况 >=
return day;
return 0-day;
}
bool Date::JudgeLeap(int year) //检查该年是否为闰年
{
if(_year%4 == 0 && _year%100 != 0 || _year%400 == 0)
return true; //是闰年
return false;
}
int Date::InitDay(const Date& d) //初始化该年的每月的天数
{
//浪费掉下标为0的位置
int day[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
if(JudgeLeap(d._year))
{
day[2] = 29;
}
return day[d._month];
}
static int CountWeek(int year, int month)//计算要求月的第一天是星期几
{
if (year >= 1600 && month >= 1)
{
int week = 6;//1600.1.1 为周六(设置日期原点)
int day = 0;
Date d1(1600,1,1);
Date d2(year, month, 1);
day=d2-d1;//统计目标月份的第一天与日期原点相差多少天
week = day%7+week;
if (week > 7)
{
week -= 7;
}
return week;
}
return -1; //当要求日历的年份月份小于1600.1.1时不做处理
}
void PrintDate(int year, int month) //打印日历
{
int day=1;
int i=0,j=0;
int week = CountWeek(year, month);
if(week != -1)
{
cout<<year<<"年"<<month<<"月"<<endl;
cout<<"日"<<" 一"<<" 二"<<" 三"<<" 四"<<" 五"<<" 六"<<endl;
Date d(year,month,1);
for (;i < week; i++)
{
cout<<" ";
}
for (j = 0; j < 6; j++) //j控制最多输出多少行
{
for (; i < 7; i++) //i控制每行输出日期的个数
{
if (day <= d.InitDay(d))
{
printf("%2d ",day);
day++;
}
else
break;
}
i = 0;
cout << endl;
}
}
else
{
cout<<"您的输入有误,不可计算此日历"<<endl;
return ;
}
}
bool Date::operator==(const Date& d)
{
return _year == d._year &&
_month == d._month &&
_day == d._day;
}
bool Date::operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month > d._month)
{
return true;
}
else if (_month == d._month)
{
if (_day > d._day)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
Date& Date::operator=(const Date& d)
{
if(*this == d)
{
return *this;
}
this->_year=d._year; //当(*this != d)时执行,可进行连续赋值
this->_month=d._month;
this->_day=d._day;
return *this;
}
bool Date::operator<(const Date& d)
{
if (_year < d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month < d._month)
{
return true;
}
else if (_month == d._month)
{
if (_day < d._day)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"
void test1() //日期加减天数
{
Date d1(2016,8,6);
d1.Display();
////Date d2=d1+24;
////Date d2=d1+80;
//Date d2=d1+501;
//d2.Display();
////2016-8-30 2016-10-25 2017-12-19
Date d2=d1-80;
d2.Display(); //2016-5-18
}
void test2() //日期减日期
{
int day = 0;
Date d1(2016,8,6);
//Date d2(2016,8,31);
Date d2(2016,10,5);
//Date d2(2017,10,1);
day=d2-d1;
cout<<"相差:"<<day<<"天"<<endl;//25 60 421
}
void test3()
{
Date d1(2016,8,6);
Date d2(d1);
Date d3(2016,9,5);
//cout<<(d1 == d2)<<endl; //1 ==
//cout<<(d1 == d3)<<endl; //0 ==
//cout<<(!(d1 == d2))<<endl; //0 !=
d1.Display(); //2016-8-6
d1=d3;
d1.Display(); //2016-9-5
cout<<(d1 < d2)<<endl; //0 <
cout<<(!(d1 < d2))<<endl; //1 >=
cout<<(d1 > d3)<<endl; //0 >
cout<<(!(d1 > d3))<<endl; //1 <=
}
void test4()
{
int year=0,month=0;
cin>>year>>month;
PrintDate(year,month);
}
int main()
{
//test1();
//test2();
//test3();
test4();
system("color 03");
system("pause");
return 0;
}