前言

给定两个日期(年月日)要求计算出 这两个日期之间的天数。在生活中我们也总会遇到这样的问题,仔细一想,虽然计算的方法不难,但是真正算起来还是要花费一点时间的,而且在这个过程中很容易因为不细心而得出错误的结果。当我们每次遇到这个问题时,总不能每次都心算或是手算吧?所以呢,写出一个简单的计算两日期之间天数的程序还是有点用的。

分析

虽说这个过程并不复杂,但是我们还是要分析一下:

  1. 日期是否符合生活规律(即不能出现月为13或是日期出现40的情况)
  2. 给定日期时不一定是小的在前大的在后
  3. 计算两日期之间天数的算法

至于日期是否符合生活规律写个判断就可以了,这个很简单,在这里就不赘述,程序中默认给定的日期是正确的,给定日期的先后顺序也我们可以写一个判断并进行位置交换,至于大的在前还是小的在前按你自己的习惯都行,下面的分析以小的在前大的在后为基准并且已经解决日期规范问题。
最最最关键的当然还是计算天数的方法:
写计算天数的算法时我们需要考虑:年份是同年还是不同年,并且我们还要考虑到是否为闰年的情况。同年的情况下还有是否同月的情况,若是同月,将日相减便得到结果,这也是最简单的一种情况。考虑到还有是否闰年,年份是否同年的情况,若是我们这样分那就会有很多种组合,程序也会显得很杂乱。那么我们怎么才能让计算的过程相对更简单呢?
在这里,我就分两种情况:

  • 同年
  • 不同年

1):同年的情况下为了不再区分是否同月,我们计算出:(大的日期到年初的天数-小的日期到年初的天数)
2):不同年的情况下,计算出:(小的日期到年末的天数+大的日期到年初的天数+年份差之间的天数)
对于不同年,我们计算小的日期到年末的天数我们还可以计算当前年的总天数-小的日期到年初的天数,所以最后就变成了(大的日期到年初的天数-小的日期到年初的天数+年份差之间的天数)注意此处的年份差之间的天数与2)中的不同,相差1.
为了再简单点,我们再将这两种情况视为一种情况:即不管什么情况,计算出(大的日期到年初的天数-小的日期到年初的天数+年份差之间的天数),因为同年份时的年份差之间的天数为零。

实现

先放上完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
using namespace std;
const int leepMonth[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
const int noLeepMonth[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
const int year[2] = { 365, 366 };
typedef struct Date {
int year;
int month;
int day;
int isLeep;
} Date;
void isLeep(Date &date) {
if ((date.year % 4 == 0 && date.year % 100 != 0) || date.year % 400 == 0)
date.isLeep = 1;
date.isLeep = 0;
}
void swap(Date &min, Date &max) {
Date temp;
if (min.year > max.year || (min.year == max.year && min.month > max.month)
|| (min.year == max.year && min.month == max.month && min.day > max.day)) {
temp = min;
min = max;
max = temp;
}
}
int diff(Date &min, Date &max) {
isLeep(min);
isLeep(max);
swap(min, max); //保证小的日期在前大的在后
int minday = 0, maxday = 0, diff = 0;
for (int m = 1; m < min.month; m++) { //计算小的日期到年初的天数,最后还要加上日期中的天数
if (min.isLeep)
minday += leepMonth[m];
else
minday += noLeepMonth[m];
}
for (int m = 1; m < max.month; m++) { //计算大的日期到年初的天数,最后还要加上日期中的天数
if (max.isLeep)
maxday += leepMonth[m];
else
maxday += noLeepMonth[m];
}
minday += min.day; //加上天数
maxday += max.day;
for (Date y = min; y.year < max.year; y.year++) { //计算年份差之间的天数
isLeep(y);
diff += year[y.isLeep];
}
diff = diff + maxday - minday; //得出结果
return diff;
}
int main() {
Date startDate, endDate;
cout << "please input startday(yyyy MM dd):";
cin >> startDate.year >> startDate.month >> startDate.day;
cout << "please input endday(yyyy MM dd):";
cin >> endDate.year >> endDate.month >> endDate.day; //日期先后不影响,swap()确保小的在前
cout << "daydiff: " << diff(startDate, endDate) << endl;
}

为了程序的可读性,这里定义了一个结构体Date,为了计算年份差之间的天数更方便,结构体中还定义了一个isLeep成员,结合数组year[2]={355,356}可以更简单的计算出年份差之间的天数,这部分的完整代码挖出来以便更好理解:

1
2
3
4
for (Date y = min; y.year < max.year; y.year++) {
isLeep(y);
diff += year[y.isLeep];
}

isLeep()函数判断当前年是否为闰年,并对结构体成员isLeep初始化.
为闰年时year[y.isLeep]year[1]=366,不是闰年时year[y.isLeep]year[0]=365