zoukankan      html  css  js  c++  java
  • 用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

  • 相关阅读:
    LightOJ 1094
    hdu 2586
    hdu 5234
    hdu 2955
    LightOJ 1030 数学期望
    poj 1273
    CodeIgniter学习笔记(十五)——CI中的Session
    CodeIgniter学习笔记(十四)——CI中的文件上传
    CodeIgniter学习笔记(十三)——CI中的分页
    CodeIgniter学习笔记(十二)——CI中的路由
  • 原文地址:https://www.cnblogs.com/kingshow123/p/whatdate.html
Copyright © 2011-2022 走看看