前言
生活中,我们时不时会遇到算天数的问题:高考倒计时、考研倒计时、过年倒计时......
想解决这些问题无非就是实现一个年月日的计算器,那要怎么来实现呢?
下面就让我们来探究一下。
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就-1 if (_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就-1 if (_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; }