编程珠玑之第三章习题4

问题描述:

4.编写处理如下日期的函数:给定两个日期,计算两者之间的天数;给定一个日期,返回值为周几;给定月和年,使用字符数组生成该月的日历。

问题解析:

1、本章主要考虑的是对数据结构的合理组织,那么本题当然也与数据结构的选择有必然的联系,应该尽量从合理组织数据结构的角度去解决问题。

2、那么如何在尽量不考虑语言自带的类库(如关于日期,大多数编译器都自带处理类库)下去解决问题?

3、这里我们考虑给定的日期不涉及“时分秒”,只有“年月日”的情况下。

4、年需判断是平年(365天)和闰年(366天)

5、给定一个日期,我们不能得出是周几,也不知道日期、周之间的必然联系,假设我知道当前的日期以及是周几,那么我能不能以此为基例,向前或向推的给定日期的是周几呢?下面给出的解决方案就是以此假设为基础。下面写一下推算周几的具体分析过程:

(1)假设我们知道某一天是周几, 那么我们以此为起点(第0天),向前推计算该天之前的,向后推计算之后的。比如2015-1-39 是星期四, 那么以此为基例,有如下分析结果:

编程珠玑之第三章习题4_第1张图片

6、解决了前面的这些问题,生成日历的要求就会变得简单。

解决方案:

方案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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <iostream>
#include <cassert>
#include <cmath>   // abs()
using  namespace std;

// 每个月的天数(平年)
const  int DAYS_EVERYMONTH[ 13] = { 0312831303130313130313031};
const  int WEEKNUM =  7// 一周7天
enum WEEK{ Sun =  0, Mon, Tues, Wed, Thur, Fri, Sat};

typedef  struct date
{
     int year;
     int month;
     int day;
    date( int y= 1970int m= 1int d= 1){  year = y; month = m, day = d; }
}DateTime;



/************************************************************************/
// 函数名称:is_leap_year
// 函数目的:判断是否是闰年
// 函数参数:year年份
// 函数返回:返回一年中的天数
// 使用条件:year > 0
// 其他说明:闰年有2种情况:(1)可以被400整除的正整数
//           (2)不能被100整除,但可以被4整除的正整数
/************************************************************************/

bool is_leap_year( const  int year)
{
    assert( year >  0 );
     return ( year %  400 ==  0 || ( year %  100 !=  0 && year %  4 ==  0) );
}

/************************************************************************/
// 函数名称:days_of_year
// 函数目的:返回一年中的天数(平年365天、闰年366天)
// 函数参数:year年份
// 函数返回:返回一年中的天数
// 使用条件:year > 0
/************************************************************************/

int days_of_year( const  int year)
{
    assert( year >  0 );
     return is_leap_year(year) ?  366 :  365;
}

/************************************************************************/
// 函数名称:gone_days
// 函数目的:已经过去的天数
// 函数参数:日期dateTime
// 函数返回:返回已经过去的天数
/************************************************************************/

int gone_days( const DateTime& datetime)
{
     int gonedays = datetime.day;
     for ( int i =  0; i < datetime.month; i++){
        gonedays += DAYS_EVERYMONTH[i];   // 按平年来算
    }

     // 判断闰年的情况
     if (datetime.month >  2 && is_leap_year(datetime.year)){  gonedays +=  1;}

     return gonedays;
}

// 比较两个日期大小
int cmpdate( const DateTime& date1,  const DateTime& date2)
{
     if (date1.year == date2.year){
         if (date1.month == date2.month) {  return date1.day <= date2.day; }
         else {  return date1.month < date2.month ;}
    }

     return date1.year < date2.year;
}

/************************************************************************/
// 函数名称:diff_days
// 函数目的:计算给定的两个日期间天数
// 函数参数:日期dateTime
// 函数返回:返回两个日期之间的天数
// 使用条件:datetime1.year <= datetime1.year
/************************************************************************/

int diff_days( const DateTime& date1,  const DateTime& date2)
{
    assert( cmpdate(date1, date2) );

     int diffdays, gonedays1, gonedays2;
    gonedays1 = gone_days(date1);
    gonedays2 = gone_days(date2);

     if ( date1.year != date2.year ) {  // 不是同一年时
        diffdays = days_of_year(date1.year) - gonedays1 + gonedays2;
         for (  int i = date1.year +  1; i < date2.year; i++){
            diffdays += days_of_year(i);
        }
    }
     else { diffdays = gonedays2 - gonedays1; }

     return diffdays;
}

/************************************************************************/
// 函数名称:get_day_of_week
// 函数目的:给定一个日期计算是周几
// 函数参数:日期dateTime
// 函数返回:一个日期计算是周几
// 使用条件:
/************************************************************************/

int get_day_of_week( const DateTime& date)
{
     // 以现在的值作为常量值
     const DateTime cur_date( 2015129);
     const  int dayweek =  4;

     int days =  0;    // days表示间隔天数
     if (cmpdate(cur_date, date)) { days = diff_days(cur_date, date); }
     else { days = -diff_days(date, cur_date); }

     // 以cur_date日期表示第0天, 星期几是固定不变的,以此为基例,向前或向后推算
     //const int firstday = 0;

     int  which_dayweek = (days + dayweek) % WEEKNUM;
     return  which_dayweek>= 0 ? which_dayweek : (WEEKNUM - abs(which_dayweek));     // 返回是周几
}

/************************************************************************/
// 函数名称:make_calender
// 函数目的:根据给定的年月生成日历
// 函数参数:year年份、month月份
// 函数返回:无
// 使用条件:
/************************************************************************/

void make_calender( int year,  int month)
{
    DateTime date;
    date.year = year;
    date.month = month;

     int index =  0;
     int  daysmonth = (month ==  2 && is_leap_year(year)) ? (DAYS_EVERYMONTH[month] +  1) : DAYS_EVERYMONTH[month];

    cout << year <<  "—" << month <<  " 日历如下:" << endl;
    cout <<  "Sun\tMon\tTues\tWed\tThur\tFir\tSat" << endl;
     for ( date.day =  1; date.day <= daysmonth; date.day++ ){
         int dayweek = get_day_of_week(date);
         if (date.day ==  1){
             while (index < dayweek){cout <<  "\t"; index++; }
        }
        cout << date.day <<  "\t";
         if ( dayweek % WEEKNUM ==  6) { cout << endl; }
    }

     return;
}


int main()
{
    DateTime datetime1( 2014212);
    DateTime datetime2( 2015129);

    cout <<  "两个日期之间的天数:" << diff_days(datetime1, datetime2) << endl;
    cout <<  "2014-2-12是星期 " << get_day_of_week(datetime1) << endl;
    make_calender( 20142);

     return  0;
}

输出结果如下:

编程珠玑之第三章习题4_第2张图片

注:解决本题是站在C语言的角度去解决,但有时为了方便,可能会夹杂C++的数据处理方式,整体上是偏C语言的,所以会显得不那么“面向对象”。望见谅!

心得疑惑:

1、本题在尽量少使用类库的情况下实现的具体的需求,有时自己动手,可能会比使用内库带来更方便的灵活性,有时候还是必须自己造“轮子”,虽然“轮子”满大街都是,但当不能够满足具体需求是,就要自己造了!

2、在具体实现之前我曾考虑使用库<ctime>里提供的函数去简单实现,发现不方便,与具体需求差太多!


你可能感兴趣的:(日历,习题)