日期计算器(一)

(壹)判断某天是星期几

基本思路:

首先,我们先选择一个基准1900年1月1日(周一)

其次,我们需要算出X年X月X日与1900年1月1日相差多少天(D1),(D1)包括:(1)X年1月1日与1900年1月1日相差多少天(D2)(2)X年X月1日与X年1月1日相差多少天(D2)(3)X年X月X日与X年X月1日相差多少天(D3)。计算D1需要判断平闰年并用循环相加,计算D2需要构造一个关于平闰年月份天数的数组并用循环相加,D3=X日中的X。

最后,我们取D1除以7的余数,余数是几就是星期几(余0即周日)。

代码如下:

#include<stdio.h>
//判断平闰年
int leap_(int year)
{
    if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
        return 1;
    else
        return 0;
}
//算出D1
int D1_(int year)
{
    int i = 0, D1 = 0;
    for(i = 1900; i < year; i++)
    {
        if(leap_(i) == 1)
            D1 += 366;
        else
            D1 += 365;
    }
    return D1;
}
//算出D2
int D2_(int year, int month)
{
    int l_[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//l代表leap闰年
    int c_[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//c代表common平年
    int i = 0,D2 = 0;
    int leap = leap_(year);
    for(i = 1; i < month; i++)
    {
        if(leap == 1)
            D2 += l_[i];
        else
            D2 += c_[i];
    }
    return D2;
}
//定义一个输出除7余几的函数
int re_(int D)
{
    return D % 7;
}
int main()
{
    int year, month, day;
    scanf("%d %d %d", &year, &month, &day);
    int D = 0, re = 0;
    D = D1_(year) + D2_(year, month) + day;
    re = re_(D);
    if(re_(D) == 0)
        re = 7;
    printf("%d年%d月%d日是星期%d", year, month, day, re);
    return 0;
}

对代码的完善:

可能在某些情况下,我们输入的月份或者天数与实际不相符合,而上述代码中并没有体现纠错的功能,下面我们对其增添一个判断是否输入错误的函数:

在上述代码的re_函数后面添加如下代码:

int error_(int year, int month, int day)
{
    int l_[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//l代表leap闰年
    int c_[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//c代表common平年

if(year < 1900)
        return 0;
    if(month < 1 || month > 12)
        return 0;
    if(leap_(year) == 1 && day > l_[month])//“== 1”可以省
        return 0;
    if(leap_(year) == 0 && day > c_[month])
        return 0;
    return 1;
}
int main()

    int year, month, day;
    while(1)
    {
        scanf("%d %d %d", &year, &month, &day);
        if(error_(year, month, day) == 0)
        {
            printf("Date is error!Please input again:\n");
        }
        else
            break;
    }
    int D = 0, re = 0;
    D = D1_(year) + D2_(year, month) + day;
    re = re_(D);
    if(re_(D) == 0)
        re = 7;
    printf("%d年%d月%d日是星期%d", year, month, day, re);
    return 0;
}

这样写出来的代码虽然看起来很长,且毋庸置疑一定有别的方法更快更简洁,但对于我这样的初学者而言,这样写思路较为清晰,不容易出错,准确率更高,减少面向答案编程的情况。

(贰)计算某两天相差多少天

[法一]:

基本思路:

上一题中我们以1900年1月1日为基准点,计算X年X月X日与1900年1月1日相差多少天,我们可以以此为启发,不妨以公元0年1月1日为基准点(公元前的日期就不算了哈),分别计算Y年Y月Y日和Z年Z月Z日与公元0年1月1日相差多少天,不妨分别设为D1天和D2天,|D1-D2|即为二者相差的天数。

代码如下:

#include<stdio.h>
//判断平闰年
int leap_(int year)
{
    if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
        return 1;
    else
        return 0;
}
//算出D1
int D1_(int year)
{
    int i = 0, D1 = 0;
    for(i = 0; i < year; i++)
    {
        if(leap_(i) == 1)
            D1 += 366;
        else
            D1 += 365;
    }
    return D1;
}
//算出D2
int D2_(int year, int month)
{
    int l_[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//l代表leap闰年
    int c_[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//c代表common平年
    int i = 0,D2 = 0;
    int leap = leap_(year);
    for(i = 1; i < month; i++)
    {
        if(leap == 1)
            D2 += l_[i];
        else
            D2 += c_[i];
    }
    return D2;
}
int main()
{
    int year1, month1, day1, year2, month2, day2;
    scanf("%d %d %d", &year1, &month1, &day1);
    scanf("%d %d %d", &year2, &month2, &day2);
    int D1 = D1_(year1) + D2_(year1, month1) + day1;
    int D2 = D1_(year2) + D2_(year2, month2) + day2; 
    int D = ((D1 > D2) ? (D1 - D2) : (D2 - D1));
    printf("%d年%d月%d日与%d年%d月%d日相差%d天", year1, month1, day1, year2, month2, day2, D);
    return 0;
}

这个代码与(壹)中代码类似,为了增强简洁性,笔者省去了判断输入格式是否正确的代码,有兴趣的读者可以自行添加(能发到评论区更是我的荣幸)

[法二]:

基本思路:

手撕,直接暴力拆解两个日期的年、月、日,进行差值运算。整体思路与[法一]大同小异,复杂度比[法一]更高,故笔者不再赘述,有兴趣的读者可以自行完成。此外,C语言中还提供了标准库函数<time.h>,可以更方便的计算日期,由于笔者的能力有限,故在此不再叙述,有兴趣的读者可以自行查阅。待笔者学习以后更新也可。

(叁)计算某日之后X天的日期

基本思路:

首先构造出平闰年月份天数的数组,并可以将某年某月的天数返回

其次利用“进位思想”,天数超过本月的天数时,月份加1,天数重置为1;当月数超过12时,年份加1,月份重置为1;

最后利用循环的手段,实现“进位”过程

代码如下:

#include<stdio.h>
int leap_(int year)
{
    return ((year % 4 == 0 && year % 100 != 0)|| year % 400 == 0);
    //若为闰年,则括号里为真,返回值为1;反之,若为平年,则括号里为假,返回值为0。
}
int day_(int year, int month)
{
    int l_[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int c_[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(leap_(year) == 1)
        return l_[month];
    else
        return c_[month];
}
int main()
{
    int year = 0, month = 0, day = 0, N = 0, i = 0;
    scanf("%d %d %d", &year, &month, &day);
    scanf("%d", &N); 
    for(i = 1; i <= N; i++)
    {
        day++;
        if(day > day_(year, month))
        {
            day = 1;//“进位”,天数重置为1。
            if(month > 12)
            {
                month = 1;//“进位”,月数重置为1。
                year++;
            }
            else{
                month++;
            }
        }
    }
    printf("%d年%d月%d日", year, month, day);
    return 0;
}

(肆)计算某日之前X天的日期

基本思路:

与上一题思路基本相同,运用“借位思想”,当天数小于1时,月数要减1,天数重置为上月天数的数值;如果月数小于1时,年数要减1,月数重置为12。利用循环的手段进行“借位”过程。

代码如下:

#include<stdio.h>
int leap_(int year)
{
    return ((year % 4 == 0 && year % 100 != 0)|| year % 400 == 0);
    //若为闰年,则括号里为真,返回值为1;反之,若为平年,则括号里为假,返回值为0。
}
int day_(int year, int month)
{
    int l_[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int c_[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(leap_(year) == 1)
        return l_[month];
    else
        return c_[month];
}
int main()
{
    int year = 0, month = 0, day = 0, N = 0, i = 0;
    scanf("%d %d %d", &year, &month, &day);
    scanf("%d", &N); 
    for(i = 1; i <= N; i++)
    {
        day--;
        if(day < 1)
        {
            if(month >= 2)
            {
                month--;
                day = day_(year, month);
            }
            else
            {
                year--;
                month = 12;
                day = 31;
            }
        }
    }
    printf("%d年%d月%d日", year, month, day);
    return 0;
}

以上为四道有关日期编程的问题解答,之后会陆续更新,感谢您的耐心阅读与对笔者的信任。如果对我的方法有疑问,敬待您的留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值