日期计算

按闰年规则确定二月天数,再依次扣除每月天数定位日期。

OJ: shumeng

题目 ID: CSP201509B

难度:入门

标签:模拟日期

日期: 2026-07-31 16:21

形式化题目

给定年份 yy1900y20151900 \le y \le 2015)和该年的第 dd 天(1d3651 \le d \le 365),输出对应的月份和日期。闰年的 2 月有 29 天。

思路

先看一个从 1 月 1 日逐日推进的基准程序,它一天一天地数,直观但常数较大:

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-31 16:21
 * update_at: 2026-08-17 22:55
 */
// brute.cpp:从 1 月 1 日开始逐日推进。
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int year, target_day;
    cin >> year >> target_day;

    // 从 1 月 1 日开始逐日推进,走满 target_day 天。
    int month = 1, day = 1;
    bool leap = year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
    int days[13] = {0, 31, 28, 31, 30, 31, 30,
                    31, 31, 30, 31, 30, 31};
    if (leap) days[2] = 29;
    for (int count = 1; count < target_day; count++) {
        day++;
        if (day > days[month]) {
            month++;
            day = 1;
        }
    }
    cout << month << '\n' << day << '\n';
    return 0;
}

brute.cpp 每走一天就更新日期,逻辑最贴近直觉,适合作为对拍基准。正式做法按月处理,更快:

  1. 闰年判断:年份是 400 的倍数,或是 4 的倍数但不是 100 的倍数,则 2 月有 29 天,否则 28 天。
  2. 逐月扣除:从 1 月开始,用 d 依次减去每个月天数;第一次不能再减时,当前月份就是答案,剩下的 d 就是该月内的日期。

代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-31 16:21
 * update_at: 2026-08-17 22:55
 */
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int year, day;
    cin >> year >> day;

    // 每月天数,2 月根据闰年规则改为 29 天。
    int days[13] = {0, 31, 28, 31, 30, 31, 30,
                    31, 31, 30, 31, 30, 31};
    if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) days[2] = 29;

    // 依次扣除每个月,剩余的天数就是该月内的日期。
    int month = 1;
    while (day > days[month]) {
        day -= days[month];
        month++;
    }
    cout << month << '\n' << day << '\n';
    return 0;
}

复杂度

  • 时间:最多处理 12 个月,O(1)O(1)
  • 空间:常量空间,O(1)O(1)

总结

日期换算先判断闰年,再把“年内第几天”逐月消耗,能避免手写复杂的月份边界公式。逐日模拟和逐月扣除是同一思路的两种粒度,前者易懂、后者高效。