【C++】日期类实现(实现简易万年历)

几点注意事项

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;
		}
	}
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值