前言
生活中,我们时不时会遇到算天数的问题:高考倒计时、考研倒计时、过年倒计时......
想解决这些问题无非就是实现一个年月日的计算器,那要怎么来实现呢?
下面就让我们来探究一下。
1.了解日期计算器的需求
1.1 表面需求
实现日期计算器无非有以下这些需求:
日期+天数得到新日期(原日期不变)
Date& operator+=(int day);
日期-天数得到新日期(原日期不变)
Date& operator-=(int day);
日期+天数,得到新日期(原日期改变)
Date operator+(int day);
日期-天数,得到新日期(原日期改变)
Date operator-(int day);
以及最常用的:两个日期相减,算天数
int operator-(const Date& d);
1.2 潜在需求
要想实现以上几个需求,我们还必须要存在判断两个日期是否相等的函数存在:
判断两个日期是否等于
bool operator==(const Date& x);
判断两个日期是否不等于
bool operator!=(const Date& x);
判断两个日期是否大于
bool operator>(const Date& x);
判断两个日期是否小于
bool operator<(const Date& x);
判断两个日期是否大于等于
bool operator>=(const Date& x);
判断两个日期是否小于等于
bool operator<=(const Date& x);
前置++ ,前置--
Date& operator++();
Date& operator--();
后置++,后置--
Date operator++(int);
Date operator--(int);
以及一个最重要的接口函数:判断大小月、闰平月
int GetMonthDay(int year, int month);
2. 需求实现
构造函数实现
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (_year < 1 || _month < 1 || _month>12 || _day<1 || _day>GetMonthDay(_year, _month)){//assert(false);//如果日期输入错误,暴力中断程序Print();cout << "日期错误" << endl;//如果日期输入错误,温柔地警告日期错误}
}
打印函数实现
void Date::Print()
{cout << _year << "-" << _month << "-" << _day << endl;
}
接口函数,判断大小月、润平月函数实现
int Date::GetMonthDay(int year, int month)
{assert(year >= 1 && month >= 1 && month <= 12);//检查日期是否合法//定义一个数组存储12个月int arrmonth[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//如果是闰年2月,返回29天if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)){return 29;}return arrmonth[month];
}
赋值运算符重载函数实现
判断两个日期是否等于、不等于、大于、小于、大于等于、小于等于
//赋值运算符重载函数实现
//d1==d2
bool Date::operator==(const Date& x)
{return _year == x._year && _month == x._month && _day == x._day;
}
//d1!=d2
bool Date::operator!=(const Date& x)
{return !(*this == x);//*this为d1,x为d2,这里相当于调用了operator==
}
//d1>d2
bool Date::operator>(const Date& x)
{if (_year > x._year){return true;}else if (_year == x._year && _month > x._month){return true;}else if (_year == x._year && _month == x._month && _day > x._day){return true;}return false;
}
//d1<d2
bool Date::operator<(const Date& x)
{return !(*this >= x);//复用operator==和operator>
}
//d1>=d2
bool Date::operator>=(const Date& x)
{return *this == x || *this > x;//复用operator==和operator>
}
//d1<=d2
bool Date::operator<=(const Date& x)
{return !(*this > x);//复用operator>
}
运算符重载函数实现
日期+天数得到新日期实现(+=原日期不变)
//日期+天数得到新日期实现(+=原日期不变)
Date& Date::operator+=(int day)
{if (day < 0)//避免输入负数{return *this -= (-day);//这里operator+=与operator-=互相调用}_day += day;while (_day > GetMonthDay(_year, _month))//当_day<=一个月的天数时,终止循环{_day -= GetMonthDay(_year, _month);//每减过一个月的天数,month就+1++_month;if (_month == 13){_year++;_month = 1;}}return *this;
}
日期-天数得到新日期实现(-=原日期不变)
//日期-天数得到新日期实现(-=原日期不变)
Date& Date::operator-=(int day)
{if (day < 0)//避免输入正数{return *this += (-day);//这里operator+=与operator-=互相调用}_day -= day;while (_day <= 0)//当_day>0时,终止循环{--_month;//每进一次循环month就-1if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);//计算完year与month后,令day加这个月天数}return *this;
}
前置++与前置--重载
//前置++重载
Date& Date::operator++()
{*this += 1;//这里复用operator+=//前置++,先加后用,因此返回+1之后的日期//this出作用域未销毁,因此返回this的地址,以&做返回值return *this;
}
//前置--重载
Date& Date::operator--()
{*this -= 1;return *this;
}
后置++与后置--重载
//后置++重载
Date Date::operator++(int)
{Date tmp(*this);//创建临时变量tmp,调用拷贝构造,tmp拷贝this*this += 1;//后置++,先用后加,因此返回+1之前的tmp//tmp出作用域被销毁,因此直接返回tmp的值,无需用&return tmp;
}
//后置--重载
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}
日期+-天数,得到新日期
//日期+-天数,得到新日期,返回Date类型
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;//复用operator+=return tmp;
}
Date Date::operator-(int day)
{Date tmp(*this); tmp -= day;//复用operator -=return tmp;
}
倒计时,两个日期相减,算天数
//两个日期相减,算天数,返回int类型
int Date::operator-(const Date& x)
{// 假设左大右小int flag = 1;Date max = *this;Date min = x;// 假设错了,左小右大if (*this < x){ max = x;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n * flag;
}
3.测试
测试d1与d2相隔多少天
int main()
{Date d1(2002, 7, 12);d1.Print();Date d2(2002, 7, 7);d2.Print();//测试d1与d2相隔多少天int ret1 = d1 - d2;cout << ret1 << endl;return 0;
}
我的结果:
电脑结果:
测试d1+10000天是何年何月何日
int main()
{Date d1(2002, 7, 12);d1.Print();Date d2(2002, 7, 7);d2.Print();//测试d1+10000天是何年何月何日Date ret2 = d1 + 10000;ret2.Print();return 0;
}
我的结果:
电脑结果:
测试d1-10000天是何年何月何日
int main()
{Date d1(2002, 7, 12);d1.Print();Date d2(2002, 7, 7);d2.Print();//测试d1-10000天是何年何月何日Date ret3 = d1 - 10000;ret3.Print();return 0;
}
我的结果:
电脑结果:
测试前置++与后置++
int main()
{Date d1(2002, 7, 12);d1.Print();Date d2(2002, 7, 7);d2.Print();//测试前置++与后置++Date ret4 = ++d1;d1.Print();ret4.Print();cout << endl;Date ret5 = d1++;d1.Print();ret5.Print();return 0;
}
4. 源代码
Date.h
#pragma once#include <iostream>
#include <assert.h>using namespace std;class Date
{
public://构造函数(全缺省)Date(int year = 2002, int month = 7, int day = 7);//打印函数void Print();//判断大小月、闰平月int GetMonthDay(int year, int month);//赋值运算符重载函数//bool类型,判断两个日期是否等于、不等于、大于、小于、大于等于、小于等于bool operator==(const Date& x);bool operator!=(const Date& x);bool operator>(const Date& x);bool operator<(const Date& x);bool operator>=(const Date& x);bool operator<=(const Date& x);//运算符重载函数//日期+天数得到新日期(原日期不变)Date& operator+=(int day);//日期-天数得到新日期(原日期不变)Date& operator-=(int day);//前置++与后置++重载Date& operator++();Date operator++(int);//前置--与后置--重载Date& operator--();Date operator--(int);//日期+-天数,得到新日期,返回Date类型Date operator+(int day);Date operator-(int day);//两个日期相减,算天数,返回int类型int operator-(const Date& d);private:int _year;int _month;int _day;
};
Date.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"//构造函数实现
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;if (_year < 1 || _month < 1 || _month>12 || _day<1 || _day>GetMonthDay(_year, _month)){//assert(false);//如果日期输入错误,暴力中断程序Print();cout << "日期错误" << endl;//如果日期输入错误,温柔地警告日期错误}
}//打印函数实现
void Date::Print()
{cout << _year << "-" << _month << "-" << _day << endl;
}//判断大小月、润平月函数实现
int Date::GetMonthDay(int year, int month)
{assert(year >= 1 && month >= 1 && month <= 12);//检查日期是否合法//定义一个数组存储12个月int arrmonth[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//如果是闰年2月,返回29天if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)){return 29;}return arrmonth[month];
}//赋值运算符重载函数实现
//d1==d2
bool Date::operator==(const Date& x)
{return _year == x._year && _month == x._month && _day == x._day;
}
//d1!=d2
bool Date::operator!=(const Date& x)
{return !(*this == x);//*this为d1,x为d2,这里相当于调用了operator==
}
//d1>d2
bool Date::operator>(const Date& x)
{if (_year > x._year){return true;}else if (_year == x._year && _month > x._month){return true;}else if (_year == x._year && _month == x._month && _day > x._day){return true;}return false;
}
//d1<d2
bool Date::operator<(const Date& x)
{return !(*this >= x);//复用operator==和operator>
}
//d1>=d2
bool Date::operator>=(const Date& x)
{return *this == x || *this > x;//复用operator==和operator>
}
//d1<=d2
bool Date::operator<=(const Date& x)
{return !(*this > x);//复用operator>
}//运算符重载函数实现
//日期+天数得到新日期实现(+=原日期不变)
Date& Date::operator+=(int day)
{if (day < 0)//避免输入负数{return *this -= (-day);//这里operator+=与operator-=互相调用}_day += day;while (_day > GetMonthDay(_year, _month))//当_day<=一个月的天数时,终止循环{_day -= GetMonthDay(_year, _month);//每减过一个月的天数,month就+1++_month;if (_month == 13){_year++;_month = 1;}}return *this;
}
//日期-天数得到新日期实现(-=原日期不变)
Date& Date::operator-=(int day)
{if (day < 0)//避免输入正数{return *this += (-day);//这里operator+=与operator-=互相调用}_day -= day;while (_day <= 0)//当_day>0时,终止循环{--_month;//每进一次循环month就-1if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);//计算完year与month后,令day加这个月天数}return *this;
}
//前置++重载
Date& Date::operator++()
{*this += 1;//这里复用operator+=//前置++,先加后用,因此返回+1之后的日期//this出作用域未销毁,因此返回this的地址,以&做返回值return *this;
}
//后置++重载
Date Date::operator++(int)
{Date tmp(*this);//创建临时变量tmp,调用拷贝构造,tmp拷贝this*this += 1;//后置++,先用后加,因此返回+1之前的tmp//tmp出作用域被销毁,因此直接返回tmp的值,无需用&return tmp;
}
//前置--与后置--和++相同的道理
Date& Date::operator--()
{*this -= 1;return *this;
}
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}
//日期+-天数,得到新日期,返回Date类型
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;//复用operator+=return tmp;
}
Date Date::operator-(int day)
{Date tmp(*this); tmp -= day;//复用operator -=return tmp;
}
//两个日期相减,算天数,返回int类型
int Date::operator-(const Date& x)
{// 假设左大右小int flag = 1;Date max = *this;Date min = x;// 假设错了,左小右大if (*this < x){ max = x;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n * flag;
}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"int main()
{Date d1(2002, 7, 12);d1.Print();Date d2(2002, 7, 7);d2.Print();cout << endl;//测试d1与d2相隔多少天int ret1 = d1 - d2;cout << ret1 << endl;cout << endl;//测试d1+10000天是何年何月何日Date ret2 = d1 + 10000;ret2.Print();cout << endl;//测试d1-10000天是何年何月何日Date ret3 = d1 - 10000;ret3.Print();cout << endl;//测试前置++与后置++Date ret4 = ++d1;d1.Print();ret4.Print();cout << endl;Date ret5 = d1++;d1.Print();ret5.Print();return 0;
}