“Detailed explanation of topic selection of experimental course” realizes the perpetual calendar in C language


Title Requirements

Programming to realize perpetual calendar, requirements:

It can be initialized according to the user input or system date. If the user does not input, the monthly calendar of the month in which the system date is located will be displayed, and the current date will be highlighted;

You can query according to the date entered by the user, display the monthly calendar of the month in which the query result is located, highlight the current date, and prompt whether to use leap year

Refuse to query and prompt any illegal input data.

Xiaobian recommends a studentClanguage/C++Learning skirt【 712284705], whether you are Daniel or Xiaobai, want to change careers or enter a career, you can come to understand, make progress and learn together! There are development tools in the skirt, and many dry goods and technical data are shared!


Detailed tips

Thinking and programming can be divided into the following modules:

  1. How to calculate the week of the required date from the existing date and week?
  2. How to output monthly calendar neatly?
  3. How to get the system time?
  4. How to beautify the interface on the premise of spare power?

The following gives a rough overview of the above problems.

Specific implementation and technical things refer to the following code.


Question 1 date calculation

As we all know, the simulation problems that need to calculate the date are cancer problems

There are many algorithms for date estimation. Here is only my idea:

  1. How many days was the launch.
  2. Deduce week by mathematical formula.

This formula is  \ ((w+d) \mod 7\)  , D stands for the number of bad days, and W stands for the day of the week.

I use the standard  0 means sun  And 6 represents the method of sat.

Time. H comes with TM_ WDAY is represented in this way.

It should be noted that  Characteristics (SHA) and (BI) of modulo of negative numbers in C and C + + , So in order to get the right result, we need to use a little skill.

if(w1+d<0) w2=(w1+d)+(-w1-d)/7*7+7; 

It seems that you can also multiply by 86400 after the launch days, subtract it, and then throw it to Localtime () to push the week.

But you even pushed out the number of days. Isn’t it fragrant directly. And since it’s a perpetual calendar, what if the number of seconds is too big

Next, let’s consider how to calculate the difference in days.

For the convenience of calculation, all calculations are based on Wednesday, January 1, 2020.

The standardization pushed by a benchmark can save a lot of trouble.

First, the first method is violence simulation. Push year by year, month by month, day by day.

What I commented out in the code is the violence simulation method.

There’s nothing to say about this. Leap years are 366 days short, otherwise 365 days short.

Push the year to the month, and make a table of the days of each month. Don’t forget to judge February.

You can also not be lazy like me, push and use it for a month  Prefix and array + leap year special judgment  That’s fine. However, each query can be pushed for up to 12 months, and it’s not much worse to push it every month.

This time is invisible to the naked eye. So whatever.

There’s nothing to say about the number of days. I casually think about two dates in the same year and month. If there is a difference of a few days, I can soon see that it’s directly subtracting the date.

In fact, it is not difficult for us to find that the year can not be simulated year by year, but can be calculated by mathematical formula.

Now we have to calculate  January 1, a to January 1, B  After several leap years.

Take a < B as an example

I won’t do the metaphysical thing of counting leap years directly with (B-A) / 4. I hope the number of leap years is absolutely accurate.

Therefore, we can:

We know that X / 4 can represent the number of multiples of 4 in positive integers less than or equal to X.

We need to find the number of leap years. We only need to know the number of multiples of 4, 100 and 400 in the interval [a, B-1].

(because I think about January 1. If I think about December 31, it should be [a + 1, b])

According to the inclusion exclusion principle, note that the number of multiples of 4, 100 and 400 is  \ (c_1,c_2,c_3\)

We have:  \ (n = c_1 – c_2 + c_3\)

according to  Prefix and  We have the following ideas:

\(c_1 = (B-1)/4 – (A-1)/4\)

No one can’t understand the prefix and, but I’d better explain.

Because a is included in the interval, we require the interval weight of [a, B-1]. Naturally, a cannot be deleted, so A-1 should be used.

The same is true for the other items.

So we calculated the number of leap years, so  \ (d = (B-A) + n \times 1\)

For the case of a > b, similarly, just change the interval to [b, A-1].

Then according to the prefix and, you will find   The formula is the same, but the sign has changed, so there is no need for classified discussion  。

In this way, the most critical problems are solved, and the rest only need to use knowledge and experience  patience  Just simulate.

Question 2 format of monthly calendar

Just Baidu the perpetual calendar or click the time in the lower right corner to imitate its format. Here are some tips.

Branch printf (everyone seems to know this)

char s[]="you bao da me.";
	"I too vegetable le.\nI do not have %d pens.\n"
	"You too strong le.\n%s\n"
	"I also want as strong as No.%d.\n",5,s


utilize  %-* d   It can be aligned to the left,  %* d   It is aligned to the right.

In short, calculate the required character length and allocate it. It doesn’t look good. Try it a few more times.

Reduce workload by using character array

char wday_[7][7]={"Sun. |","Mon. |","Tues.|","Wed. |","Thur.|","Fri. |","Sat.  "};
char div_line[]="============================================================";

Note that the string length of a two-dimensional array must be declared. Because memory can be allocated only when the length is known. The two-dimensional array not only allocates the memory of the first string, but also allocates the remaining memory at intervals. If the length is not specified, it does not know where to put the second string.

(the following is my personal understanding, because I had this problem at the beginning)

Also, it is not recommended to set the length of the character array just right.   printf(“%s”,wday_[1])   What I read is   wday_ [1] Pointer without knowing   wday_ [1]   How long is it (because the memory allocation of two-dimensional array is continuous), I really only use six characters   “Sun. |”   But together, it’s like this in the eyes of the computer   “Sun. |Mon. |”   In other words, because they are connected together, there is no string termination mark in the middle,% s will output your entire two-dimensional array.  Reserve at least one more bit in advance  Can solve this problem.

In addition, I found that   div_ line[]   The default allocation is exactly 61 chars in length. In other words, there is no reserved seat behind this thing. If I declare a string SS with the space after it in a subsequent operation, I   printf(“%s”,div_line)   Will you also output SS when you are?

Interesting. Let’s take a picture of this problem and study it later.

Question 3Simple usage of

This Baidu pile, do not repeat. Personally, I prefer it   This article

I am here  Reprint  A piece of code:

struct tm {  
int tm_ sec; /*  Seconds – the value range is [0,59]*/  
int tm_ min; /*  Score value range is [0,59]*/  
int tm_ hour; /*  When - the value range is [0,23]*/  
int tm_ mday; /*  The date of a month - value range is [1,31]*/  
int tm_ mon; /*  Month (from January, 0 represents January) - the value range is [0,11]*/  
int tm_ year; /*  Year, which is equal to the actual year minus 1900*/  
int tm_ wday; /*  Week - the value range is [0,6], where 0 represents Sunday, 1 represents Monday, and so on*/ 
int tm_ yday; /*  The number of days from January 1 of each year - the value range is [0365], where 0 represents January 1, 1 represents January 2, and so on*/  
int tm_ isdst; /*  Daylight saving time identifier, when daylight saving time is implemented, TM_ Isdst is positive. No daylight saving time, TM_ Isdst is 0; When you don't know the situation, TM_ Isdst() is negative*/  

It should be noted that  tm_ Year returns the difference, and TM_ Mon starts at 0

Put code and comments directly.

int main(){
    struct tm *t; /* Because the return values of the two functions used below are pointers*/
    /*time_ T is actually an integer. Long or int may be different*/
    time_t x;
    /*There are two ways to use the time function to get the number of seconds elapsed from the base time to the present time*/
    time(&x);/* You can use time to change the value corresponding to the pointer &x*/
    x=time(NULL); /* The return value of time is also the number of seconds, so it's OK to write it like this*/ 
    /*Null can also be changed to any pointer, but in this way, the number corresponding to that pointer will be modified, which needs attention*/
    t=localtime(&x);/* Get the local time corresponding to x seconds (UTC + 8)*/
    t=gmtime(&x);/* You can also use this function to obtain UTC standard time*/
    /*Then you can use the things in the above structure*/
    printf("Now is %d\n",t->tm_year+1900);
    return 0;

Question 4 beautification

Based on my understanding of the CMD interface, I think changing the color can make it look better (FOG)

In fact, Lxy boss introduced me to the method of changing string color with printf,   But it seems too troublesome. I’m too lazy to do it. If I’m interested, I can try Baidu myself.

For common CMD commands, you can enter help in the CMD window or use “/?” such as color /? Such commands are used to query details

useThe system function in can run the CMD command. (probably)

The dividing line is also very nice. Um. It’s nice. (convinced)

Of course you have to roll the GUI, when I didn’t say (escape)

Effect picture: it turns out that leaving a few spaces in front of each line will look better, but I don’t really want to change it.

This is a convenient marker for quickly skipping pictures~

By the way, ask for hack without award. Maybe the week of which date is wrong. At least I haven’t found anything wrong now.

Oh, by the way, I’m worried that someone’s base year is not 1900, so I added a fix mode


Code base

#define PAUSE() system("pause")
#define CLEAR() system("cls")
#define rep(i,a,b) for(int i=a;i<=b;i++)
char wday_[7][7]={"Sun. |","Mon. |","Tues.|","Wed. |","Thur.|","Fri. |","Sat.  "};
char div_line[]="============================================================";
char _16bas[]="0123456789abcdef";
void color_change(){
    /*change the color of cmd in random*/
    static char cmd_[] = "color f0";
void _statement(){
        "Welcome to use Permanent Calendar by Qing_!\n"
        "Here, you can see the monthly calendar now.\n"
        "Here, you can query the calendar for anyday.\n"
        "Come on, study-human! Now, enjoy your time!\n"
        "Notice: I will use Chinese English to talk with you.\n"
    PAUSE(); CLEAR();
void put_space(int x){ while(x) x--,putchar(' '); }
void i_am_doing(){
    /*To tell user that I'm calucating.*/
    static int cc=0,p=0;
    cc=(cc+1)%25; if(cc>0) return;

    printf("\n%s\nNow calucating\n",div_line);
    rep(i,1,p) putchar('.'); putchar('\n');


struct DATE{ int year,mon,day,wday; };
int c_day[]={0,31,0,31,30,31,30,31,31,30,31,30,31};
int bas_Y=1900;

void Fix_Mode(){
    /* May be your bas_Y is not 1900. */
    color_change(); CLEAR();
        "%s\nHere is Fix-Mode.\n"
        "This is an important step.\nPlease input a correct year.\n"
        "Before use, input the year today like this:\n2020\n"
        "To fix the base year of different system.\n%s\n",div_line,div_line
    printf("The year today is:"),scanf("%d",&bas_Y);
    time_t now; time(&now);
    struct tm *t=localtime(&now);
    printf("Done. Press any key to see the change.\n");
void input_date(struct DATE *A,int y,int m,int d,int w){
    /* Maybe i havenot use this */
    A->day=d; A->mon=m; A->year=y; A->wday=w;
void get_date(struct DATE *A,struct tm *t){
    /* Notice: tm_year is a delta with 1900, tm_mon is [0,11] */
    A->day=t->tm_mday; A->mon=t->tm_mon+1; 
    A->wday=t->tm_wday; A->year=t->tm_year+bas_Y;
int is_leap_year(int year){
    return year%100==0 ? year%400==0 : year%4==0;
int legal_judge(struct DATE *Q){
    if(Q->day<=0||Q->mon<=0) return 0;
    if(Q->mon>12||Q->day>31) return 0;
    if(Q->mon==2) return is_leap_year(Q->year)?Q->day<=29:Q->day<=28;
    return Q->day<=c_day[Q->mon];
int get_wday(int wday,int delta){
    return wday<0?wday-wday/7*7+7:wday%7;
int get_day(struct DATE *Q){
    if(Q->mon==2) return is_leap_year(Q->year)?29:28;
    return c_day[Q->mon];
void _display(struct DATE *Q){
    /* To display the date. */
    /* The head */
    if(is_leap_year(Q->year)) printf("Do you know? %d is a leap year ~\n",Q->year);
    else printf("Wuhu, i want to fly ~\n");
    printf("Here: %d-%d\n",Q->year,Q->mon);
    rep(i,0,6) printf("%s",wday_[i]); putchar('\n');
    /* what day is it? */
    int _wday=get_wday(Q->wday,-Q->day+1),mDAY=get_day(Q);
    rep(i,0,_wday-1) put_space(2),putchar('/'),put_space(2),putchar('|');
        printf(i!=Q->day?" %2d  ":"[%2d] ",i);
        rep(i,_wday,5) put_space(2),putchar('/'),put_space(2),putchar('|');
void calc_wday(struct DATE *Q){
    /* Base on 2020-1-1 Wed. */
    int delta=0,by=2020,bm=1,bd=1;
        by++; i_am_doing();
        by--; i_am_doing();

        if(bm==2) delta+=is_leap_year(by)?29:28;
        else delta+=c_day[bm];
        bm++; i_am_doing();
void Query_Mode(){
    color_change(); CLEAR();
        "\n%s\nWelcome to Query-Mode!\n"
        "In this mode, you can input a date like this:\n"
        "1969 11 9\n"
        "And I will show you the monthly calendar of the date.\n"
        "Notice not to input an illegal date.\n"
        "If, you do that, I may point it out.\n"
        "When you want to exit this mode, input three \'0\':\n"
        "0 0 0\n"
        "Enjoy your time!\n%s\n\n",div_line,div_line
    struct DATE Q; 
        color_change(); CLEAR();
        printf("Now tell me what date you want to query:\n");
            color_change(); CLEAR();
            printf("\n%s\nThanks for your use!\n",div_line);
            printf("Now press any key to exit Query_Mode.\n%s\n\n",div_line);
            PAUSE(); return;
            printf("You input an illegal date! Try again!\n");
            calc_wday(&Q); CLEAR();
            /* display */
            /* ask for another */
                "I have show you the calendar.\n"
                "Now press any key to come back.\n"
                "If you want to exit this mode, input \'0 0 0\' next time.\n"


int main(){
        time_t sec_; time(&sec_);
        struct tm *p; p=localtime(&sec_);
        struct DATE now; get_date(&now,p);
        /* Display the date today. */
        color_change(); CLEAR();
        printf("Today is a good day!\n");
        /* Ask for next option. */
            "What do you want to do now?\n"
            "Input an opt as follow to tell me.\n"
            "1 - to query some date.\n"
            "2 - to fix year.\n"
            "3 - to exit.\n"
            "If you input something else, \n"
            "I will change the color for you.\n"
        int opt;
        printf("%s\nInput option:\n",div_line),scanf("%d",&opt);
        if(opt==1) Query_Mode();
        if(opt==2) Fix_Mode();
            color_change(); CLEAR();
            printf("%s\nSee you next time!\n%s\n",div_line,div_line);
            PAUSE(); break;
    return 0;


If you’re rightInterested in programming and want to learn more. Here we share material packages and learning resources, as well as open courses (including basic knowledge and project practice tutorials).

(including c)LanguageC++WindowsQtLinux)~Whether Xiaobai or advanced, you can grow here.Point I enter the learning base