事情的起因是前端同事一时性起想自己写一个日历控件
然后研究了一下逻辑思路
我们参考一下win10系统的显示格式
从日期数据来说,这是一个6X7的矩阵
除了当月的天数以外,头尾还要补齐上月末与下月初的日期。
首先,需要确定本月显示的天数,那么第一件事,得判断当前月共有多少天,包括闰年的处理
int getdays(int year,int month){ switch(month){ case 12: return 31;case 11: return 30;case 10: return 31;case 9: return 30;case 8: return 31;case 7: return 31;case 6: return 30;case 5: return 31;case 4: return 30;case 3: return 31;case 2: if((year%400==0)||(year%4==0)&&(year%100!=0))return 29;else return 28;case 1: return 31;case 0: return 31;} }
注意,这里加了一个case 0,因为下文中会引用到求上月份天数,如果是1月份的上个月,即传入0,那么实际返回的应是去年的12月所以是31天。
确定好本月以后,我们推一下上个月需要的天数,首先就要确定本月的一号在矩阵的位置,也就是周几。拿上图为例,其排列是周一至周日。
那么如果是周日(7),则需要补上6天,即,需要补的天数为当前月1号的星期-1
那么求当前月1号的星期也可以通过本日的日期信息获取(week-(day-1)%7)这个应该不难理解,即计算日期的差值,如果求出的值小于1那么就再加上7
这样我们就能求出开始需要补充的天数了。
后面追加的天数更为简单,直接初始成1号往后加就好了
大体思路确定了以后,我们开始过一遍这个6*7矩阵
首先是头部分,我用一个自减变量来标记他,这样做的好处是,我可以直接用上个月的天数减去这个变量求得应该显示的日期,比如说我本月的1号是在周日
那么就需要补充上月的6天,我第一个显示的就是31(上个月天数)-(6-1)即26号,最后显示31-0=31号
if(needday-->0)
{
time_table[i][j]=Pdays-needday;
printf("%02d%c",time_table[i][j],j==6?'\n':' ');
}
然后是本月的正常日期,也可以加上后面追加的一起算,只要把超过当前天数时,天数清空就好了。即:
time_table[i][j]=day_count++;
if(day_count>days)
{
day_count=1;
}
printf("%02d%c",time_table[i][j],j==6?'\n':' ');
下面贴出完整代码:
#include<stdio.h>#include<time.h>#include<stdlib.h>#include<windows.h>#include<string.h>using namespace std;int i,j;int time_table[6][7];int getdays(int year,int month){ switch(month){ case 12: return 31;case 11: return 30;case 10: return 31;case 9: return 30;case 8: return 31;case 7: return 31;case 6: return 30;case 5: return 31;case 4: return 30;case 3: return 31;case 2: if((year%400==0)||(year%4==0)&&(year%100!=0))return 29;else return 28;case 1: return 31;case 0: return 31;} }int main(){SYSTEMTIME sys;GetLocalTime( &sys ); HANDLE consolehwnd;consolehwnd=GetStdHandle(STD_OUTPUT_HANDLE); /* printf("%d\n",sys.wYear); printf("%d\n",sys.wMonth); printf("%d\n",sys.wDay); printf("%d\n",sys.wDayOfWeek); printf("%d\n",sys.wHour); printf("%d\n",sys.wMinute); printf("%d\n",sys.wSecond); printf("%d\n",sys.wMilliseconds); */int days=getdays(sys.wYear,sys.wMonth);int Pdays=getdays(sys.wYear,sys.wMonth-1);// printf("%d\n",days);int day_count=1;int FirstDayWeekAsMonth=sys.wDayOfWeek-(sys.wDay-1)%7;if(FirstDayWeekAsMonth<1) FirstDayWeekAsMonth+=7;// printf("%d\n", FirstDayWeekAsMonth);int needday=FirstDayWeekAsMonth-1;printf("%s\n", "一 二 三 四 五 六 日");SetConsoleTextAttribute(consolehwnd,FOREGROUND_INTENSITY|FOREGROUND_GREEN);for(i=0;i<6;i++) for(j=0;j<7;j++) { if(needday-->0) { time_table[i][j]=Pdays-needday; SetConsoleTextAttribute(consolehwnd,FOREGROUND_RED); printf("%02d%c",time_table[i][j],j==6?'\n':' ');SetConsoleTextAttribute(consolehwnd,FOREGROUND_INTENSITY|FOREGROUND_GREEN); } else { time_table[i][j]=day_count++; printf("%02d%c",time_table[i][j],j==6?'\n':' '); if(day_count>days) { day_count=1; SetConsoleTextAttribute(consolehwnd,FOREGROUND_INTENSITY|FOREGROUND_BLUE); } } }SetConsoleTextAttribute(consolehwnd, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);// for(i=0;i<6;i++)// for(j=0;j<7;j++)// printf("%02d%c",time_table[i][j],j==6?'\n':' '); return 0;}
运行截图
注:GetLocalTime实现获取当前日期信息,SetConsoleTextAttribute实现改变控制台输出颜色,为了区别月份