几点注意事项
1. 解决闰年问题
通常情况下,根据“四年一闰,百年不闰,四百年一闰”的原则可以解决大多数问题,但根据儒略历(1582年10月4日之后使用的是格里高利历,也就是现在的公历)记法,1582年前都是“四年一闰”,也就是说世纪年也是闰年(如1500年,1700年),所以这里需要做一个特判。
2. 解决星期几的问题
这里根据蔡勒公式
w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1(1582年10月4日之后)
w=5-c+y+[y/4]+[13*(m+1)/5]+d-1(1582年10月4日之前)
w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
y:年(年数后两位数)
c:世纪-1(年数前两位数-1,如果是公元1年~公元99年,则默认此时世纪为“零世纪”(当然没有零世纪)此时c为-1,这里不讨论公元前)
d:日
m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
最后计算w时,为了防止w为负数,因此对w % 7之后再加7
3. 对于运算符重载
对于"<<"、">>"的重载与其他的运算符重载有些不同,这里用到了友元函数。4.代码中还有一些日期类的实现
最后最后最后,作者能力水平有限,还请多多包容( ・´ω`・ )
.h文件
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
//菜单
void menu();
//日期类
class Date
{
private:
int _year;
int _month;
int _day;
//对于 << , >> 的运算符重载
//如果是定义在类里面,第一个参数默认是this(左操作数),那么在使用时就必须写成 d << cout
//解决这种问题就需要把函数放在全局,这样就能自定义参数列表,但因为类的访问限制,此时有两种解决方法
//1.定义GetYear(),GetMonth(),GetDay()函数(不推荐)
//2.使用友元
//友元
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
bool judge() const;
Date(int year = 1, int month = 1, int day = 1);//初始化
int GetMonthDay(int year, int month) const;//获取每个月的天数
int GetWeek(int d = 1) const;//获取星期
void PrintMonth() const;//打印月历
void PrintYear() const;//打印年历
bool is_LeapYear() const;//判断是否是闰年
//d + day
Date operator+(int day) const;
//d += day
Date& operator+=(int day);
//d ++
Date& operator++();
//++ d
Date operator++(int);
//d --
Date operator--(int);
//-- d
Date& operator--();
//d - day
Date operator-(int day) const;
//d1 - d2
int operator-(const Date& d) const;
//d -= day
Date& operator-=(int day);
//d1 == d2
bool operator==(const Date& d) const;
//d1 != d2
bool operator!=(const Date& d) const;
//d1 < d2
bool operator<(const Date& d) const;
//d1 <= d2
bool operator<=(const Date& d) const;
//d1 > d2
bool operator>(const Date& d) const;
//d1 >= d2
bool operator>=(const Date& d) const;
};
.c文件
#include"Date.h"
//菜单
void menu()
{
cout << "====================欢迎使用日期计算器====================" << endl;
cout << "=============请根据如下提示输入相应编号选择功能===========" << endl;
cout << "==========1.计算几天后的日期(负数表示向前计算)==========" << endl;
cout << "================2.打印两个日期中间相隔天数================" << endl;
cout << "=========3.打印某年某月的日历 4.打印某年的日历=========" << endl;
cout << "=========================0.退出===========================" << endl;
}
//判断日期是否合法
bool Date::judge() const
{
if (_year < 1 || _month < 1 || _month>12 || _day < 1 || _day > GetMonthDay(_year, _month))
{
return false;
}
return true;
}
//获取星期
int Date::GetWeek(int d) const
{
//蔡勒公式:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1(1582年10月4日之后)
// w=5-c+y+[y/4]+[13*(m+1)/5]+d-1(1582年10月4日之前)
//w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
//y:年(年数后两位数)c:世纪-1(年数前两位数)d:日
//m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
if (_year < 1582 || (_year == 1582 && _month < 10) || (_year == 1582 && _month == 10 && _day <= 4))
{
int year = _year;
int month = _month;
if ((_month == 1) || (_month == 2))
{
year -= 1;
month += 12;
}
int c = int(year / 100);
int y = year - 100 * c;
//***一定要注意带方括号取整数的算式,要加上int的强制类型转换
int w = 5 - c + y + (int)(y / 4) + (13 * (month + 1) / 5) + d - 1;//蔡勒公式1582年10月4日前的算法
w = (w % 7 + 7) % 7;//处理负数的情况
return w;
}
else
{
int year = _year;
int month = _month;
if ((_month == 1) || (_month == 2))
{
year -= 1;
month += 12;
}
int c = int(year / 100);
int y = year - 100 * c;
//计算当前月份第一天为星期几,d==1
//***一定要注意带方括号取整数的算式,要加上int的强制类型转换
int w = y + (int)(y / 4) + (int)(c / 4) - 2 * c + (13 * (month + 1) / 5) + d - 1;//蔡勒公式1582年10月4日后的算法
w = (w % 7 + 7) % 7;//处理负数的情况
return w;
}
}
//打印月历
void Date::PrintMonth() const
{
cout.width(5);
cout << "日";
cout.width(5);
cout << "一";
cout.width(5);
cout << "二";
cout.width(5);
cout << "三";
cout.width(5);
cout << "四";
cout.width(5);
cout << "五";
cout.width(5);
cout << "六" << endl;
int w = GetWeek();
for (int i = 0; i < w; i++)//处理第一行空白处
{
cout.width(5);
cout << " ";
}
for (int i = 0; i < 7 - w; i++)//处理第一行日期
{
if (_year == 1582 && _month == 10 && i == 4)
{
cout.width(5);
cout << 15;
cout.width(5);
cout << 16;
break;
}
cout.width(5);
cout << i + 1;
}
cout << endl;
int count = 0;
for (int i = 7 - w; i < GetMonthDay(_year, _month); i++)
{
if (this->_year == 1582 && this->_month == 10 && i == 6)
{
i += 10;
}
cout.width(5);
cout << i + 1;
count++;
if ((count) / 7 == 1)
{
cout << endl;
count = 0;
}
}
cout << endl;
}
//打印年历
void Date::PrintYear() const
{
Date tmp(*this);
for (int i = tmp._month; i <= 12; i++)
{
cout << endl;
cout.width(17);
cout << tmp._year << "年" << tmp._month << "月" << endl;
cout << "====================================" << endl;
tmp.PrintMonth();
tmp._month++;
cout << "====================================" << endl;
}
}
//对象实例化
Date::Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{}
//判断是否为闰年
bool Date::is_LeapYear() const
{
if (_year > 1582 && (_year % 4 == 0 && _year % 100 != 0) || (_year % 400 == 0))
{
return true;
}
else if (_year <= 1582 && _year % 4 == 0)
{
return true;
}
else
{
return false;
}
}
//获取该月的总天数
int Date::GetMonthDay(int year, int month) const
{
assert(month > 0 && month < 13);
int monthArray[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && is_LeapYear())
{
return 29;
}
else
{
return monthArray[month];
}
}
//d + day
Date Date::operator+(int day) const
{
//2次拷贝
Date tmp(*this);
tmp._day += day;
/*while (tmp._day > GetMonthDay(tmp._year, tmp._month))
{
tmp._day -= GetMonthDay(tmp._year, tmp._month);
tmp._month++;
if (tmp._month == 13)
{
tmp._year++;
tmp._month = 1;
}
}*/
return tmp;
}
//d += day
Date& Date::operator+=(int day)
{
if (day < 0)
{
*this -= -day;
return *this;
}
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
if (_month == 13)
{
_year++;
_month = 1;
}
}
/*return *this = *this + day;*/ //3次拷贝
return *this;
}
//d - day
Date Date::operator-(int day) const
{
Date tmp(*this);
tmp -= day;
return tmp;
}
//d1 - d2
int Date::operator-(const Date& d) const
{
Date d1(*this);
Date d2(d);
int flag = -1;
if (d1 < d2)
{
Date tmp = d1;
d1 = d2;
d2 = tmp;
flag = 1;
}
int day = 0;
while (d1 != d2)
{
--d1;
++day;
}
return flag * day;
}
//d -= day
Date& Date::operator-=(int day)
{
if (day < 0)
{
*this += -day;
return *this;
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
//++ d d.operator++();
Date& Date::operator++()
{
*this += 1;
return *this;
}
//d ++ d.operator++(0);(编译器会自动传这个int,int仅仅是为了占位)
Date Date::operator++(int)
{
//前置++效率更高,不用拷贝
Date tmp(*this);
*this += 1;
return tmp;
}
//-- d
Date& Date::operator--()
{
*this -= 1;
return *this;
}
//d --
Date Date::operator--(int)
{
Date tmp(*this);
*this -= 1;
return tmp;
}
//d1 == d2
bool Date::operator==(const Date& d) const
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
//d1 != d2
bool Date::operator!=(const Date& d) const
{
return !(_year == d._year
&& _month == d._month
&& _day == d._day);
}
//d1 < d2
bool Date::operator<(const Date& d) const
{
if (_year < d._year)
{
return true;
}
else if (_year == d._year && _month < d._month)
{
return true;
}
else if (_year == d._year && _month == d._month && _day < d._day)
{
return true;
}
else
{
return false;
}
/*return (_year < d._year)
|| (_year == d._year && _month < d._month)
|| (_year == d._year && _month == d._month && _day < d._day);*/
}
//d1 <= d2
bool Date::operator<=(const Date& d) const
{
return *this < d || *this == d;
}
//d1 > d2
bool Date::operator>(const Date& d) const
{
return !(*this <= d);
}
//d1 >= d2
bool Date::operator>=(const Date& d) const
{
return !(*this < d);
}
//cout << d
ostream& operator<<(ostream& out, const Date& d)
{
int week = d.GetWeek(d._day);
out << d._year << "年" << d._month << "月" << d._day << "日";
switch (week)
{
case 0:
cout << "星期日";
break;
case 1:
cout << "星期一";
break;
case 2:
cout << "星期二";
break;
case 3:
cout << "星期三";
break;
case 4:
cout << "星期四";
break;
case 5:
cout << "星期五";
break;
case 6:
cout << "星期六";
break;
}
return out;
}
//cin >> d
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
#include"Date.h"
int main()
{
menu();
int input = 1;
while (input)
{
end6:
cout << "请用按键选择相应的服务:";
cin >> input;
switch (input)
{
case 1://1.计算几天后的日期(负数表示向前计算)
{
Date d1;
int n = 0;
end1:
cout << "请输入日期(空格隔开):";
cin >> d1;
if (!d1.judge())
{
cout << "日期非法,请重新输入" << endl;
goto end1;
}
cout << "请输入天数(负数表示向前计算):";
cin >> n;
d1 += n;
if (!d1.judge())
{
cout << n << "天后的日期是非法日期" << endl;
break;
}
cout << n << "天后的日期是:" << d1 << endl;
cout << endl;
cout << "请继续使用" << endl;
break;
}
case 2://2.打印两个日期中间相隔天数
{
Date d2;
Date d3;
end2:
cout << "请输入日期(空格隔开):";
cin >> d2;
if (!d2.judge())
{
cout << "日期非法,请重新输入" << endl;
goto end2;
}
end3:
cout << "请输入日期(空格隔开):";
cin >> d3;
if (!d3.judge())
{
cout << "日期非法,请重新输入" << endl;
goto end3;
}
cout << "两日期相差 " << d2 - d3 << " 天(负数表示向前计算)" << endl;
cout << endl;
cout << "请继续使用" << endl;
break;
}
case 3://3.打印某年某月的日历
{
end4:
cout << "请输入要打印日历的年和月:";
int year = 0;
int month = 0;
cin >> year >> month;
Date d4(year,month);
if (!d4.judge())
{
cout << "日期非法,请重新输入" << endl;
goto end4;
}
cout << year << "年" << month << "月日历为:" << endl;
d4.PrintMonth();
cout << endl;
cout << "请继续使用" << endl;
break;
}
case 4://4.打印某年的日历
{
end5:
cout << "请输入要打印日历的年份:";
int year = 1;
int month = 1;
cin >> year;
Date d5(year, month);
if (!d5.judge())
{
cout << "日期非法,请重新输入" << endl;
goto end5;
}
d5.PrintYear();
cout << endl;
cout << "请继续使用" << endl;
break;
}
case 0:
cout << "感谢使用:)";
break;
default:
cout << "输入错误,请重新输入" << endl;
goto end6;
}
}
}