日期是公历日期,即某年某月某日;天数指的是公历纪年的天数,即公元元年(1年)1月1日作为第一天,其他天数依次类推。
在Win10系统中使用VS2022的C++实现。
在VS2022中创建空项目,添加文件“main.cpp”,并输入如下代码:
#include <iostream>
#include <math.h>
// 一个100年(非第四个100年)包含的天数 24个闰年76个平年
#define _100_years_day_ (24*366+76*365)
// 一个400年包含的天数
// 前三个100年包含24个闰年76个平年;第四个100年是25个闰年75个平年
#define _400_years_day_ ((24 * 366 + 76 * 365) * 3 + 25 * 366 + 75 * 365)
// 一个4年包含的天数,3个平年,一个闰年:(3*365+366)
#define _4_years_day_ (3*365+366)
// 判断年份year是否是闰年.
bool is_leap_year(int year)
{
bool bRes = false;
// 若year不是4的倍数,则不是闰年
if (year % 4 != 0) return false;
// 若year是4的倍数、但不是100的倍数,则是闰年
if (year % 100 != 0) return true;
// 若year是4的倍数、并且是100的倍数、还是400的倍数,则是闰年
if (year % 400 == 0) return true;
// 若year是4的倍数、并且是100的倍数、但不是400的倍数,则不是闰年
return false;
}
// 计算year年有多少天
int get_year_days(int year)
{
// 闰年366天
if (is_leap_year(year)) return 366;
// 平年365天
return 365;
}
// 计算前n年的总天数.
int compute_n_yers_day(int n)
{
if (0 == n) return 0;
int nRes = 0;
div_t divRes; // 整数除法运算的结果
divRes = div(n, 400); // 包含几个400年
nRes += divRes.quot * _400_years_day_;
// 包含几个100年.
divRes = div(divRes.rem, 100);
nRes += divRes.quot * _100_years_day_;
// 包含几个4年
divRes = div(divRes.rem, 4);
nRes += divRes.quot * _4_years_day_;
// 余数是几个平年
nRes += divRes.rem * 365;
return nRes;
}
// 计算y年前m个月的天数(m取值范围是0到11)
int compute_month_days(int year, int m)
{
int nRes = 0;
int nFebDays = 0; // 2月份的天数.
if (is_leap_year(year)) nFebDays = 29; // 闰年29天
else nFebDays = 28; // 平年28天
switch (m) {
case 0:
nRes = 0;
break;
case 1:
nRes = 31;
break;
case 2:
nRes = 31+nFebDays;
break;
case 3:
nRes = 31+nFebDays+31;
break;
case 4:
nRes = 31+nFebDays+31+30;
break;
case 5:
nRes = 31+nFebDays+31+30+31;
break;
case 6:
nRes = 31 + nFebDays + 31 + 30 + 31+30;
break;
case 7:
nRes = 31 + nFebDays + 31 + 30 + 31 + 30+31;
break;
case 8:
nRes = 31 + nFebDays + 31 + 30 + 31 + 30 + 31+31;
break;
case 9:
nRes = 31 + nFebDays + 31 + 30 + 31 + 30 + 31 + 31+30;
break;
case 10:
nRes = 31 + nFebDays + 31 + 30 + 31 + 30 + 31 + 31 + 30+31;
break;
case 11:
nRes = 31 + nFebDays + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31+30;
break;
case 12:
nRes = 31 + nFebDays + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30+31;
break;
}
return nRes;
}
// 计算y年m月d日是第几天.
// 基准是:公元1年1月1日是第一天.
// 算法是:前(y-1)年的天数+前(m-1)个月的天数+d
int ymd_to_day(int y, int m, int d)
{
return compute_n_yers_day(y - 1) + compute_month_days(y, m-1) + d;
}
void day_to_ymd(int day, int& y, int& m, int& d)
{
// 计算年份
y = 1;
div_t divRes; // 整数除法运算的结果
divRes = div(day, _400_years_day_); // 包含几个400年
y += divRes.quot * 400;
// 包含几个100年.
divRes = div(divRes.rem, _100_years_day_);
y += divRes.quot * 100;
// 包含几个4年
divRes = div(divRes.rem, _4_years_day_);
y += divRes.quot * 4;
// 包含是几个平年
divRes = div(divRes.rem, 365);
y += divRes.quot * 1;
// 现在,利用余数计算月份和天数.
short int sDay = divRes.rem;
// 如果余数为0,表示是该年的最后一天,需做特殊处理.
if (0 == sDay) {
y -= 1;
sDay = get_year_days(y);
}
if (sDay <= compute_month_days(y, 1)) { // 小于或等于1月份的天数
m = 1; d = sDay;
}else if (sDay <= compute_month_days(y, 2)) { // 小于或等于2月份的天数
m = 2; d = sDay- compute_month_days(y, 1);
}else if (sDay <= compute_month_days(y, 3)) { // 小于或等于3月份的天数
m = 3; d = sDay - compute_month_days(y, 2);
}else if (sDay <= compute_month_days(y, 4)) { // 小于或等于4月份的天数
m = 4; d = sDay - compute_month_days(y, 3);
}else if (sDay <= compute_month_days(y, 5)) { // 小于或等于5月份的天数
m = 5; d = sDay - compute_month_days(y, 4);
}else if (sDay <= compute_month_days(y, 6)) { // 小于或等于6月份的天数
m = 6; d = sDay - compute_month_days(y, 5);
}else if (sDay <= compute_month_days(y, 7)) { // 小于或等于7月份的天数
m = 7; d = sDay - compute_month_days(y, 6);
}else if (sDay <= compute_month_days(y, 8)) { // 小于或等于8月份的天数
m = 8; d = sDay - compute_month_days(y, 7);
}else if (sDay <= compute_month_days(y, 9)) { // 小于或等于9月份的天数
m = 9; d = sDay - compute_month_days(y, 8);
}else if (sDay <= compute_month_days(y, 10)) { // 小于或等于10月份的天数
m = 10; d = sDay - compute_month_days(y, 9);
}else if (sDay <= compute_month_days(y, 11)) { // 小于或等于11月份的天数
m = 11; d = sDay - compute_month_days(y, 10);
}else if (sDay <= compute_month_days(y, 12)) { // 小于或等于12月份的天数
m = 12; d = sDay - compute_month_days(y, 11);
}
}
// 测试is_leap_year.
void test_is_leap_year(int year)
{
//int year = 100;
if (is_leap_year(year))
std::cout << "公元" << year << "年是闰年" << std::endl;
else
std::cout <<"公元" << year << "年不是闰年" << std::endl;
}
// 测试年月日和天数的互转
void test_ymd_day(int y, int m, int d)
{
// 年月日到天、天到年月日的测试
int day = ymd_to_day(y, m, d);
std::cout << "公元" << y << "年" << m << "月" << d << "日是第" << day << "天" << std::endl;
day_to_ymd(day, y, m, d); // 天数转换为年月日
std::cout << "第" << day << "天是公元" << y << "年" << m << "月" << d << "日" << std::endl;
std::cout << std::endl;
}
int main()
{
// 闰年判断函数的测试.
test_is_leap_year(1); // 不是闰年
test_is_leap_year(100); // 不是闰年
test_is_leap_year(200); // 不是闰年
test_is_leap_year(2022);// 不是闰年
test_is_leap_year(4); // 是闰年
test_is_leap_year(20); // 是闰年
test_is_leap_year(400); // 是闰年
test_is_leap_year(2000); // 是闰年
test_is_leap_year(2020); // 是闰年
// 计算第一个400年是多少天.(每个400年的天数是相同的)
int n_400_years_days = 0;
for (int i = 1; i <= 400; i++)
n_400_years_days += get_year_days(i);
std::cout << "第一个400年的天数是(第一种方法):" << n_400_years_days << std::endl;
// 也可以用如下算法计算,以检验正确性.
// 前三个100年包含24个闰年76个平年;第四个100年是25个闰年75个平年
// 所以一个400年的天数是: (24*366+76*365)*3 + 25*366+75*365
std::cout << "第一个400年的天数是(第二种方法):" << (24 * 366 + 76 * 365) * 3 + 25 * 366 + 75 * 365 << std::endl;
// 年月日到天、天到年月日的测试
int year = 1; int month = 1; int day = 1;
test_ymd_day(year, month, day);
year = 1; month = 1, day = 31;
test_ymd_day(year, month, day);
year = 1; month = 3, day = 1;
test_ymd_day(year, month, day);
year = 1; month = 12, day = 31;
test_ymd_day(year, month, day);
year = 2; month = 1, day = 1;
test_ymd_day(year, month, day);
year = 3; month = 12, day = 31;
test_ymd_day(year, month, day);
year = 4; month = 12, day = 31;
test_ymd_day(year, month, day);
year = 2022; month = 2, day = 27;
test_ymd_day(year, month, day);
}
上述代码中的核心函数是ymd_to_day和day_to_ymd,分别实现年月日到天数的转换和天数到年月日的转换;is_leap_year,判断某年是否是闰年;get_year_days,输入年份,返回该年的天数;compute_n_yers_day,计算前n年的总天数,即公元1年至n年的总天数;compute_month_days,计算某年前m个月的总天数(实现是简单的,但是不够简洁);test_is_leap_year和test_ymd_day是两个功能测试函数。 main函数主要是产生测试数据,测试上述相关函数的功能。 程序运行结果如下图所示:
?
|