问题描述:
4.编写处理如下日期的函数:给定两个日期,计算两者之间的天数;给定一个日期,返回值为周几;给定月和年,使用字符数组生成该月的日历。问题解析:
1、本章主要考虑的是对数据结构的合理组织,那么本题当然也与数据结构的选择有必然的联系,应该尽量从合理组织数据结构的角度去解决问题。
2、那么如何在尽量不考虑语言自带的类库(如关于日期,大多数编译器都自带处理类库)下去解决问题?
3、这里我们考虑给定的日期不涉及“时分秒”,只有“年月日”的情况下。
4、年需判断是平年(365天)和闰年(366天)
5、给定一个日期,我们不能得出是周几,也不知道日期、周之间的必然联系,假设我知道当前的日期以及是周几,那么我能不能以此为基例,向前或向推的给定日期的是周几呢?下面给出的解决方案就是以此假设为基础。下面写一下推算周几的具体分析过程:
(1)假设我们知道某一天是周几, 那么我们以此为起点(第0天),向前推计算该天之前的,向后推计算之后的。比如2015-1-39 是星期四, 那么以此为基例,有如下分析结果:
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] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 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= 1970, int m= 1, int 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( 2015, 1, 29); 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( 2014, 2, 12); DateTime datetime2( 2015, 1, 29); cout << "两个日期之间的天数:" << diff_days(datetime1, datetime2) << endl; cout << "2014-2-12是星期 " << get_day_of_week(datetime1) << endl; make_calender( 2014, 2); return 0; } |
输出结果如下:
注:解决本题是站在C语言的角度去解决,但有时为了方便,可能会夹杂C++的数据处理方式,整体上是偏C语言的,所以会显得不那么“面向对象”。望见谅!
心得疑惑:
1、本题在尽量少使用类库的情况下实现的具体的需求,有时自己动手,可能会比使用内库带来更方便的灵活性,有时候还是必须自己造“轮子”,虽然“轮子”满大街都是,但当不能够满足具体需求是,就要自己造了!
2、在具体实现之前我曾考虑使用库<ctime>里提供的函数去简单实现,发现不方便,与具体需求差太多!