算法入门—日期问题处理

α. 闰年判定

1、能被4整除,但不能被100整除
2、能被400整除

bool isLeepYear(int year){ // 闰年返回true
    return (!(year % 400) || (!(year % 4) && (year % 100)));
} //能被4整除而不能被100整除,能被四百整除

β. 日期推算

有时候我们遇到从某一天算起过了n天的年月日的问题,我们可以模拟一下日期的推演,在模拟的时候我们需要注意一下几点

当日期到达12月32日的时候,年数加一,日期变为一月一日
1,3,5,7,8,10月份时,如果到了32日,月份需要加一,日变为一
4,6,9,11 月份时,如果到了31日,月份需要加一,日变为一
2月份时,当年为闰年:如果到了30日,月份需要加一,日变为一
2月份时,当年为平年:如果到了29日,月份需要加一,日变为一

#include <bits/stdc++.h>
using  namespace std;
bool isLeepYear(int year){
    return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
} //能被4整除而不能被100整除,能被四百整除

int main(){
    int y = 1777;
    int m = 4;
    int d = 30;
    int n;
    scanf("%d",&n);
    for(int i = 0;i < n;i++){
        d++;
        if (m == 12 && d == 32){ // 当日期到达12月32日的时候,年数加一,日期变为一月一日
            y++;
            m = 1;
            d = 1;
            continue; // 注意 continue 的使用
        }
        if(m == 2 && isLeepYear(y) && d == 30){ // 2月份时,当年为闰年:如果到了30日,月份需要加一,日变为一
            m = 3;
            d = 1;
            continue;
        }
        if(m == 2 && !isLeepYear(y) && d == 29){ // 2月份时,当年为平年:如果到了29日,月份需要加一,日变为一
            m = 3;
            d = 1;
            continue;
        }
        // 1,3,5,7,8,10月份时,如果到了32日,月份需要加一,日变为一
        if((m == 1||m == 3||m == 5||m == 7||m==8||m==10) && d == 32){
            d = 1;
            m++;
            continue;
        }
        // 4、6、9、11 月份时,如果到了31日,月份需要加一,日变为一
        if((m == 4 || m==6 || m== 9 || m==11) && d == 31){
            d = 1;
            m++;
            continue;
        }
    }
    printf("%d %d %d",y,m,d);
    return 0;
}

γ. 某年某月有多少天

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  //平年时每个月有多少天
bool isLeepYear(int year){
    return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
} //能被4整除而不能被100整除,能被四百整除
int daysOfMonth(int year, int month){
    if(isLeepYear(year) && month == 2) return 29; // 闰年的二月
    return days[month];
}

δ. 某月某周某一天几号

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  //平年时每个月有多少天
bool isLeepYear(int year){
    return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
} //能被4整除而不能被100整除,能被四百整除
int daysOfMonth(int year, int month){
    if(isLeepYear(year) && month == 2) return 29;
    return days[month];
}
int WeekOfDate(int y, int m, int d, int week = 2) {  //根据1850年1月1日是周二,返回y年m月d日是周几
    // 遍历整年
    for (int i = 1850; i < y; ++i) {                //检查1850年到y年经历的年份
        int temp = isLeepYear(i) ? 366 : 365; 
        week = (week + temp) % 7;                                            //更新week
    }
    // 遍历整月
    for (int i = 1; i < m; ++i)                  //检查1月到m月的月份
        week = (week + daysOfMonth(y, i)) % 7;  //求出该月有几天,并更新week
        
    return (week + d - 1) % 7;                 
}

ε. 判断y年m月第b个星期c是几号

首先我们根据上面的结论得出y年m月1日为周几,再根据日推算

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  //平年时每个月有多少天
bool isLeepYear(int year){
    return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
} //能被4整除而不能被100整除,能被四百整除
int daysOfMonth(int year, int month){
    if(isLeepYear(year) && month == 2) return 29;
    return days[month];
}
int WeekOfDate(int y, int m, int d, int week = 2) {  //根据1850年1月1日是周二,返回y年m月d日是周几
    // 遍历整年
    for (int i = 1850; i < y; ++i) {                //检查1850年到y年经历的年份
        int temp = isLeepYear(i) ? 366 : 365;
        week = (week + temp) % 7;                                            //更新week
    }
    // 遍历整月
    for (int i = 1; i < m; ++i)                  //检查1月到m月的月份
        week = (week + daysOfMonth(y, i)) % 7;  //求出该月有几天,并更新week

    return (week + d - 1) % 7;
}
int DayOfDate(int y, int m, int b, int c) {  
    int week = WeekOfDate(y, m, 1);                  //确定y年m月1日是周几
    return 1 + (c + 7 - week) % 7 + 7 * (b - 1);
}

ζ. 判断日期是否合法

判断日期是否合法只需要记住以下几点(代码很好实现,就补贴出来啦,大家可以自己写一下)
月份只有1-12这12个正整数
1、3、5、7、8、10、12月份(0<=d && d<=31)
4、6、9、11月份 (0<=d && d<=30)
闰年时 2月份 (0<=d && d<=29)
平年时 2月份 (0<=d && d<=28)
年月日均为整数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值