C++ Date 类实现:仅使用自 1970 年 1 月 1 日以来的天数作为数据成员
实现数据成员仅为 '自 1970 年 1 月 1 日以来的天数' ,满足下面接口的类 Date,并进行测试。
class Date {
private:
static Date default_date; //缺省日期
....... 其他你认为必要的数据成员
public:
class Bad_date {}; //可选,成员类,用于采用“异常”策略向调用者报告错误
static void set_default(); //为缺省参数赋值
static bool leap_year(int year);//判断闰年
Date(int dd = 0, int mm = 0, int year = 0); //带有默认参数的构造函数
Date& add_year(int n); //自增 n 年,返回对象自身
Date& add_month(int n); //自增 n 月,返回对象自身
Date& add_day(int n); //自增 n 日,返回对象自身
int day()const;//返回日
int year()const;//返回年份
int month()const;//返回月份
int week()const;//返回这一天是星期几
..... 其他你认为必要的接口操作声明 ......
};
解:
我们需要实现一个 Date 类,数据成员仅为 '自 1970 年 1 月 1 日以来的天数'。这个数据成员可以用一个整数表示,比如 days_since_1970_01_01。同时,我们应该在类内部定义一个缺省日期,以及一些成员函数,比如判断闰年、增加年月日等操作,以及获取年月日、星期几等操作。
下面是一个可能的实现:
#include <iostream>
#include <stdexcept>
class Date {
private:
static const int days_per_week = 7; //一周有7天
static const int days_per_normal_year = 365; //一年有365天
static const int days_per_leap_year = 366; //一个闰年有366天
static const int days_since_1970_01_01 = 719528; //1970年1月1日距离公元0年1月1日的天数
static Date default_date; //缺省日期
int days_since_1970_01_01_; //自1970年1月1日以来的天数
int get_days_per_month(int year, int month) const; //获取某个月的天数
bool is_leap_year(int year) const; //判断是否为闰年
public:
class Bad_date {}; //可选,成员类,用于采用“异常”策略向调用者报告错误
static void set_default(); //为缺省参数赋值
static bool leap_year(int year); //判断闰年
Date(int dd = default_date.day(), int mm = default_date.month(), int yyyy = default_date.year()); //带有默认参数的构造函数
Date& add_year(int n); //自增 n 年,返回对象自身
Date& add_month(int n); //自增 n 月,返回对象自身
Date& add_day(int n); //自增 n 日,返回对象自身
int day() const; //返回日
int year() const; //返回年份
int month() const; //返回月份
int week() const; //返回这一天是星期几
friend std::ostream& operator<<(std::ostream& os, const Date& date); //输出日期
friend bool operator==(const Date& lhs, const Date& rhs); //判断是否相等
};
Date Date::default_date(1, 1, 1970);
void Date::set_default() {
default_date = Date(1, 1, 1970);
}
bool Date::leap_year(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
int Date::get_days_per_month(int year, int month) const {
switch (month) {
case 2:
return is_leap_year(year) ? 29 : 28;
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
bool Date::is_leap_year(int year) const {
return leap_year(year);
}
Date::Date(int dd, int mm, int yyyy) {
if (yyyy < 1970 || mm < 1 || mm > 12 || dd < 1 || dd > get_days_per_month(yyyy, mm)) {
throw Bad_date{};
}
int days_since_0000_01_01 = (yyyy - 1) * days_per_normal_year + (yyyy - 1) / 4 - (yyyy - 1) / 100 + (yyyy - 1) / 400;
for (int i = 1; i < mm; ++i) {
days_since_0000_01_01 += get_days_per_month(yyyy, i);
}
days_since_0000_01_01 += dd - 1;
days_since_1970_01_01_ = days_since_0000_01_01 - days_since_1970_01_01;
}
Date& Date::add_year(int n) {
int yyyy = year();
if (n > 0) {
while (n > 0) {
days_since_1970_01_01_ += is_leap_year(yyyy) ? days_per_leap_year : days_per_normal_year;
++yyyy;
--n;
}
} else if (n < 0) {
while (n < 0) {
days_since_1970_01_01_ -= is_leap_year(yyyy - 1) ? days_per_leap_year : days_per_normal_year;
--yyyy;
++n;
}
}
return *this;
}
Date& Date::add_month(int n) {
int yyyy = year();
int mm = month();
if (n > 0) {
while (n > 0) {
int days_in_month = get_days_per_month(yyyy, mm);
days_since_1970_01_01_ += days_in_month;
++mm;
if (mm > 12) {
mm = 1;
++yyyy;
}
--n;
}
} else if (n < 0) {
while (n < 0) {
--mm;
if (mm < 1) {
mm = 12;
--yyyy;
}
int days_in_month = get_days_per_month(yyyy, mm);
days_since_1970_01_01_ -= days_in_month;
++n;
}
}
return *this;
}
Date& Date::add_day(int n) {
days_since_1970_01_01_ += n;
return *this;
}
int Date::day() const {
int days_since_0000_01_01 = days_since_1970_01_01_ + days_since_1970_01_01;
int yyyy = 1;
while (days_since_0000_01_01 >= (is_leap_year(yyyy) ? days_per_leap_year : days_per_normal_year)) {
days_since_0000_01_01 -= is_leap_year(yyyy) ? days_per_leap_year : days_per_normal_year;
++yyyy;
}
int mm = 1;
while (days_since_0000_01_01 >= get_days_per_month(yyyy, mm)) {
days_since_0000_01_01 -= get_days_per_month(yyyy, mm);
++mm;
}
return days_since_0000_01_01 + 1;
}
int Date::year() const {
int days_since_0000_01_01 = days_since_1970_01_01_ + days_since_1970_01_01;
int yyyy = 1;
while (days_since_0000_01_01 >= (is_leap_year(yyyy) ? days_per_leap_year : days_per_normal_year)) {
days_since_0000_01_01 -= is_leap_year(yyyy) ? days_per_leap_year : days_per_normal_year;
++yyyy;
}
return yyyy;
}
int Date::month() const {
int days_since_0000_01_01 = days_since_1970_01_01_ + days_since_1970_01_01;
int yyyy = 1;
while (days_since_0000_01_01 >= (is_leap_year(yyyy) ? days_per_leap_year : days_per_normal_year)) {
days_since_0000_01_01 -= is_leap_year(yyyy) ? days_per_leap_year : days_per_normal_year;
++yyyy;
}
int mm = 1;
while (days_since_0000_01_01 >= get_days_per_month(yyyy, mm)) {
days_since_0000_01_01 -= get_days_per_month(yyyy, mm);
++mm;
}
return mm;
}
int Date::week() const {
return (days_since_1970_01_01_ + 4) % days_per_week + 1;
}
std::ostream& operator<<(std::ostream& os, const Date& date) {
os << date.year() << '-' << date.month() << '-' << date.day();
return os;
}
bool operator==(const Date& lhs, const Date& rhs) {
return lhs.days_since_1970_01_01_ == rhs.days_since_1970_01_01_;
}
测试代码:
#include <iostream>
int main() {
Date d1; //使用缺省日期
std::cout << d1 << std::endl; //1970-1-1
Date d2(31, 12, 2021); //指定日期
std::cout << d2 << std::endl; //2021-12-31
Date d3(29, 2, 2020); //闰年的2月29日
std::cout << d3 << std::endl; //2020-2-29
try {
Date d4(29, 2, 2021); //非闰年的2月29日,应该抛出异常
} catch (const Date::Bad_date&) {
std::cout << 'Bad date' << std::endl;
}
d2.add_year(1).add_month(-1).add_day(2); //2022-11-2
std::cout << d2 << std::endl;
Date d5 = d2.add_year(1); //2023-11-2
std::cout << d2 << std::endl;
std::cout << d5 << std::endl;
std::cout << (d2 == d5) << std::endl; //0
Date d6 = d2; //拷贝构造函数
std::cout << (d2 == d6) << std::endl; //1
return 0;
}
原文地址: https://www.cveoy.top/t/topic/nKn5 著作权归作者所有。请勿转载和采集!