用C語言寫個程序推算出是星期幾?(用泰勒公式實現)


在日常生活中,我們常常遇到要知道某一天是星期幾的問題。有時候,我們還想知道歷史上某一天是星期幾。比如:

“你出生的那一天是星期幾啊?”

“明年五一是不是星期天?我去找你玩?”

通常,解決這個問題的最簡單辦法就是看日歷,但是我們總不會隨時隨身帶着日歷,更不可能隨時隨身帶着幾千年的萬年歷。老師告訴我們,學習C語言,就是為了用它來幫助我們解決實際問題的,那么,既然我們通過《C程序設計伴侶》學了C語言,如何用C語言寫個程序來推算出自己出生的那天是星期幾呢?

答案當然是肯定的(要不然,我也不會在這里啰嗦)。要計算日期所對應的星期,有一個著名的泰勒公式:

w = [ c/4 ] – 2c + y + [y/4] + [13 * (m+1) / 5] + d – 1

其中,c是年份的前兩位,y是年份的后兩位,m是月份,d是日期,這里需要注意的是,如果是1月和2月,c和y需要按照上一年來取值。比如,我們要 計算2013年1月28日,那么,c=20,y=12(因為是1月,按照上一年取值),m=1,d=28。將這些按照日期獲得的數據帶入公式,得到的w除 以7,得到的結果是幾就是星期幾,如果是0則是星期日。另外還需要說明的是,公式中的中括號[…]表示取其中計算結果的整數部分。

按照上面的公式算法,加上我們從《C程序設計伴侶》中學到的關於函數和日期處理的知識,我們可以將這個公式的算法實現為:

// whatday.c 根據泰勒公式推算日期對應的星期
#include <stdio.h>
#include <string.h> 
#include <time.h>
  
// 根據日期推算星期
int whatday(int year,int mon,int day)
{
    int m = mon;
    int d = day;
    // 根據月份對年份和月份進行調整
    if(m <= 2)
    {
        year -= 1;
        m += 12;
    }
    int c = year / 100; // 取得年份前兩位
    int y = year % 100; // 取得年份后兩位
     
    // 根據泰勒公式計算星期
    int w = (int)(c/4) - 2*c + y + (int)(y/4)
        + (int)(13*(m+1)/5) + d - 1;
 
    
    return w%7; // 返回星期
}
  
// 將數字轉換成字符串 
char* convertday(int w,char* str)
{
    if(w<0 || w>6 || NULL == str)
        return NULL;
  
    char* days[7];
    days[0] = "Sunday";
    days[1] = "Monday";
    days[2] = "Tuesday";
    days[3] = "Wednesday";
    days[4] = "Thursday";
    days[5] = "Friday";
    days[6] = "Saturday";
 
    // 轉換
    strcpy(str,days[w]);
    
    return str;
}
int main(int argc,char* argv[])
{
    // 檢查參數
    if(argc != 1 && argc != 4)
    {
        puts("usage: whatday or whatday 2013 1 28");
        return 1;
    }
     
    int year = 0;
    int mon = 0;
    int day = 0;
    // 根據不同參數,獲取日期
    if(1 == argc)
    {
        // 如果只有一個參數,以當前日期作為查詢日期
        time_t t = time(NULL);
        struct tm* cur = localtime(&t);
    
        year = cur->tm_year + 1900;    // 年份
        mon = cur->tm_mon + 1;    // 月份
        day = cur->tm_mday;        // 日期    
    }
    else if(4 == argc)
    {
       // 將參數轉換成日期
        year = atoi(argv[1]);
        mon = atoi(argv[2]);
        day = atoi(argv[3]);
    }
    else
    {
        puts("usage: whatday.exe 1981 9 22");
        return 1;
    }    
 
    // 根據日期計算星期
    int w = whatday(year,mon,day);
    // w 有可能是負數,轉換為正
    if(w < 0)
    {
        w += 7;
    }
     
    char daystr[16] = "";
 
    // 將數字表示的星期轉換為字符串
    if(NULL != convertday(w,daystr))
    {
        // 輸出推算結果
        printf("%d-%d-%d is %s.",year,mon,day,daystr);
    }
     
    return 0;
}

編譯這個程序得到whatday.exe應用程序,使用它,我們就可以方便地推算出自己出生的那一天是星期幾了:

F:\code>gcc -o whatday.exe whatday.c

F:\code>whatday 1981 9 22
    1981-9-22 is Tuesday.

F:\code>

根據程序的推算結果,我現在終於知道了原來我是周二出生的啊。感謝泰勒老師,感謝他發現的泰勒公式(太偉大了),感謝C語言,感謝《C程序設計伴侶》,還有CCTV,MTV,感謝。。。還有人和我一樣是周二出生的嗎?

最后,雖然這種方法簡單是簡單,但是正如sw老師在平論中提到的那樣,它可能會遇到日期被人為調整的特殊情況,在這些特殊情況下,就可能有問題了。那么,要處理這些特殊情況,又該怎么辦呢?

在C語言中,解決問題的辦法永遠不止一個

我們應當時刻記住這句話。同樣,要推算某個特定日期對應的星期,也肯定不止泰勒公式這唯一的一種方法。正如sw老師在評論中提到的那樣,我們可以利用C標准庫中的時間函數mktime()和localtime()來達到同樣的目的。

首先,我們可以用分解時間(struct tm)表示我們要推測的時間點(比如,1981年9月22日),然后mktime()函數可以把用分解時間表示的這個固定的時間點轉換為日歷時劇(用time_t表示),然后再用localtime()函數將這個日歷時間轉換為分解時間,我們就可以得到這個日期對應的星期數(分解時間的tm_wday成員)。雖然整個過程稍微麻煩了一點,但是其正確性可以得到保證(即使出了問題,也該標准委員會的那些大佬們負責)。你可以按照這個思路自己實現,也可以參考下面的實現。

// whatday.c 使用C標准庫中的mktime()函數推算日期對應的星期 
#include <string.h> 
#include <time.h>
#include <stdio.h>
// 根據日期的年月日得到星期
int whatday(int year,int mon,int day)
{    
    struct tm t;   
    memset(&t,0,sizeof(t));    
    // 用年月日填充分解時間t    
    t.tm_year = year - 1900; // 減去起始年份    
t
.tm_mon = mon - 1; // 起始月份 t.tm_mday = day; // 將分解時間t轉換為日歷時間ct time_t ct = mktime(&t); if(-1 == ct) // 日期錯誤 { return -1; } else { // 用localtime()函數獲取日歷時間ct對應的 // 分解時間,其tm_wday成員就是我們需要的星期數 struct tm* bt = localtime(&ct); return bt->tm_wday; } } // 將數字轉換成字符串 char* convertday(int w,char* str) { if(w<0 || w>6 || NULL == str) return NULL; char* days[7]; days[0] = "Sunday"; days[1] = "Monday"; days[2] = "Tuesday"; days[3] = "Wednesday"; days[4] = "Thursday"; days[5] = "Friday"; days[6] = "Saturday"; // 轉換 strcpy(str,days[w]); return str; } int main(int argc,char* argv[]) { // 檢查參數 if(argc != 1 && argc != 4) { puts("usage: whatday or whatday 2013 1 28"); return 1; } int year = 0; int mon = 0; int day = 0; // 根據不同參數,獲取日期的年月日 if(1 == argc) { // 如果只有一個參數,以當前日期作為查詢日期 time_t t = time(NULL); struct tm* today = localtime(&t); year = today->tm_year + 1900; mon = today->tm_mon + 1; day = today->tm_mday; } else { // 將參數轉換成日期 year = atoi(argv[1]) ; mon = atoi(argv[2]); day = atoi(argv[3]); } // 根據年月日查詢星期幾 int w = whatday(year,mon,day); char daystr[16] = ""; // 將數字表示的星期轉換為字符串 convertday(w,daystr); // 輸出推算結果 printf("%d-%d-%d is %s.",year,mon,day,daystr); return 0; }

對比上次的代碼我們會發現,我們只是改變了whatday()函數的實現,其它代碼並沒有發生太大變化。如果你學過《C程序設計伴侶》中提到的字符串處理函數(strcha()和strcpy()以及ctime()函數),還可以將這個程序進一步簡化。到底如何進行,看過書了解這些函數后就知道了,你一定可以的。

當然,利用mktime()和localtime()函數配合使用的應用遠遠不止這些,比如,接下來我們就會用他們來計算每個月的第一個星期一所對應的日期。

轉自:http://www.howzhi.com/course/3387/lesson/43160


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM