一个日期类作为类和对象知识点的总结
注意:
因为历史上1582年10月是少了10天,并且闰年的计算规则在1582年前后是不同的,因此计算某一天是周几,直接采用了倒推的方式确定公元1年1月1日是周几,然后反过来写的。(仅仅为了省事)
Date.h
#pragma once
/* 一个类可以重载那些运算符,取决于哪些运算符对这个类型有意义! */
class Date {
public://对Date类声明友元friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);//构造函数Date(int year=1,int month = 1,int day = 1):_year(year),_month(month),_day(day){//检查日期合法性if (!checkDate()) {assert(checkDate());}}//拷贝构造Date(const Date& d) :_year(d._year),_month(d._month),_day(d._day){}//赋值重载 d1=d2=d3,最后返回d1Date& operator=(const Date& d){//防止自我赋值if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}bool isLeapYear(int year) {if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))return true;return false;}int getLeapNum(int begin, int end) {if (begin > end) return 0;int leap1 = (begin - 1) / 4 - (begin - 1) / 100 + (begin - 1) / 400;int leap2 = end / 4 - end / 100 + end / 400;return leap2 - leap1;}//获取某年某月天数,频繁调用->放在类里定义作为内联//构造频繁,直接放在类里面当作内联int getMonthDay(int year, int month) {static int months[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//如果是2月且闰年if (_month == 2 && isLeapYear(year))return 29;return months[month];}//日期合法性bool checkDate() {if (_year >= 1&& _month && _month < 13&& _day>0 && _day <= getMonthDay(_year, _month)){return true;}return false;}//比较运算符bool operator==(const Date& d);bool operator!=(const Date& d);bool operator>(const Date& d);bool operator<(const Date& d);bool operator>=(const Date& d);bool operator<=(const Date& d);//日期+-天数Date operator+(int day);Date& operator+=(int day);Date operator-(int day);Date& operator-=(int day);//operator++Date& operator++();//前置Date operator++(int);//后置//日期-日期int operator-(const Date& d);//operator--Date& operator--();Date operator--(int);int operator-(const Date& d) const;//计算是周几string DayofWeek();
private:int _year;int _month;int _day;
};//cout << d1 << d2,频繁调用,函数声明和定义不分离 直接内联
inline ostream& operator<<(ostream& out, const Date& d) {out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}//cin>>d1>>d2, 需要改变Date对象 不能用const引用
inline istream& operator>>(istream& in,Date& d) {in >> d._year >> d._month >> d._day;//检查输入日期合法assert(d.checkDate());return in;
}
Date.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;#include "Date.h"//比较运算符
bool Date::operator==(const Date& d) {return _year == d._year&& _month == d._month&& _day == d._day;
}
bool Date::operator!=(const Date& d) {return !(*this == d);
}
bool Date::operator>(const Date& d) {if (_year > d._year || _year == d._year && _month > d._month ||_year == d._year && _month == d._month && _day > d._day){return true;}return false;
}
bool Date::operator<(const Date& d) {return !(*this >= d);
}
bool Date::operator>=(const Date& d) {return *this == d || *this > d;
}
bool Date::operator<=(const Date& d) {return !(*this > d);
}//日期+=天数: d1+=d2+=100
Date& Date::operator+=(int day) {//处理day是负数的情况: +=负数 -> -=正数if (day < 0) {return *this -= -day;}//先把天数加上,然后判断是否超过当月的天数_day += day;while (_day > getMonthDay(_year, _month)) {_day -= getMonthDay(_year, _month);++_month;if (_month == 13) {++_year;_month = 1;}}return *this;
}//日期+天数 d+100是返回结果,d本身不改变
Date Date::operator+(int day) {//利用临时对象Date tmp = *this;tmp += day;return tmp;
}//日期-=天数 d1-100
Date& Date::operator-=(int day) {//-=负数-> +=正数if (day < 0) {return *this += -day;}//先减掉天数,若天数<=0 就继续借上个月的天数_day -= day;while (_day <= 0) {--_month;if (_month == 0) {_month = 12;--_year;}_day += getMonthDay(_year, _month);//借上个月}return *this;
}
Date Date::operator-(int day) {Date tmp = *this;tmp -= day;return tmp;
}//++d, 返回改变后
Date& Date::operator++() {return *this += 1;
}
//d++,返回改变前
Date Date::operator++(int) {Date tmp = *this;*this += 1;return tmp;
}//operator--
Date& Date::operator--() {return *this -= 1;
}
Date Date::operator--(int) {Date tmp = *this;*this -= 1;return tmp;
}//
// 2022-7-23 2003-4-10
// 计算2003的1月1日到2022年1月1日的差距 diff1
// 再计算处4-10和7-23分别是这一年的第几天,计算差值 diff2
// 两个差值相加即可//日期-日期
int Date::operator-(const Date& d) {//计算 年份之间差多少天//先假设大的年份是 *this的年份int max = _year; //大的年份int min = d._year; //小的年份if (_year < d._year) {max = d._year;min = _year;}//计算 [min,max]之间的 整年中的闰年个数 整年范围: [min+1,max-1]int diff1 = (max - min) * 365 + getLeapNum(min+1,max-1); //基础年数+闰年个数(闰年多1天)//计算分别是本年的第几天int diff2 = 0;int day1 = _day;for (int i = 1; i < _month; ++i) {day1 += getMonthDay(_year, i);}int day2 = d._day;for (int i = 1; i < d._month; ++i) {day2 += getMonthDay(d._year, i);}//diff2计算的是 *this和d 在这一年中 分别是第几天的差距,是 *this-ddiff2 = day1 - day2;//diff1计算的是 大年份比小年份差多少天,但目标要计算*this - d,如果d的年份大,要变一下符号。if (max == d._year) {diff1 *= -1;}return diff1 + diff2;
}//周几
string Date::DayofWeek() {//计算1.1.1到现在差多少天, 1.1.1默认周1static string weeks[] = { "周一","周二","周三","周四","周五","周六","周天" };//0对应周一 公园1,1,1是周1int n = *this - Date(1, 1, 1);int weekday = 1; //逆推1,1,1是周2weekday += n;return weeks[weekday%7];
}
测试代码
//test.cpp
//测试日期比较大小
void test_Date1()
{Date d1;Date d2(2022, 7, 15);cout << (d1 == d2) << endl;cout << (d1 <= d2) << endl;cout << (d1 >= d2) << endl;cout << (d1 < d2) << endl;}//测试+=
void test_Date2()
{Date d1(2022, 7, 23);Date d2(d1);d1 += 86;d1 += 453;d1 += 4000;Date d3 = d2 + 86;d1 += -4000;d1 += -453;d1 += -86;}//测试 -=
void test_Date3()
{Date d1(2022, 7, 23);d1 -= 86;d1 -= 453;d1 -= 4000;
}//测试 ++ 和 --
void test_Date4()
{Date d1(2022, 7, 23);++d1;--d1;Date d2 = d1 + 1;
}//测试日期 - 日期
void test_Date5()
{Date d1(2022, 7, 23);Date d2(2022, 5, 5);Date d3(2022, 8, 15);Date d4(2020, 3, 25);Date d5(2025, 12, 25);cout << (d2 - d1) << endl;cout << (d3 - d1) << endl;cout << (d4 - d1) << endl;cout << (d5 - d1) << endl;}//测试 << >>
void test_Date6()
{Date d1(2024, 11, 13);cout << d1 << endl;Date d2;cin >> d2;cout << d1 << d2 << endl;
}//测试周几
void test_Date7()
{Date d1(2024,11, 13);cout << d1.DayOfWeek() << endl;
}
int main()
{//test_Date1();//test_Date2();//test_Date3();//test_Date4();//test_Date5();//test_Date6();test_Date7();return 0;
}