Medium · calendar math

Days Between Dates

Measuring between two dates directly is a maze of carries and borrows. Instead, give every date a serial number — days elapsed since a fixed epoch — and the difference becomes one subtraction. All the calendar's ugliness hides inside the conversion, where it belongs.

At a glanceWrite <code>serial(y, m, d)</code> = whole years since the epoch + days of whole months before m + d, with leap-aware month lengths. The answer is <code>serial(y2,m2,d2) - serial(y1,m1,d1)</code>.

Problem

Input: Two lines: y1 m1 d1 and y2 m2 d2 (1900 ≤ y ≤ 2100), the first date not after the second.

Output: The number of days from the first date to the second (same date → 0).

Samples:

InputOutput
2000 1 1
2000 12 31
365
1900 2 28
1900 3 1
1

The second sample is the century trap in one line: 1900 is divisible by 100 but not by 400, so it is NOT a leap year — February had 28 days, and the gap is 1. In 2000 the same dates would be 2 apart.

Your solution

main.cpp — your solution
Custom input for "Run my input"

Judging runs in your browser against hidden tests. A runaway loop is cut off after 3 seconds — still, make sure every loop has an exit. Your code is saved in this browser as you type.

Stuck? Hints

Hint 1 — Three layers in one serial number

serial(y, m, d) adds three blocks: whole years before y (365 or 366 each — a loop from the epoch year), whole months before m in year y (a loop calling monthDays), and d itself. Each block is its own small loop; none of them needs cleverness.

Hint 2 — The leap rule is three conditions

Divisible by 4 → leap, except divisible by 100 → not leap, except divisible by 400 → leap. One line encodes all three: (y % 4 == 0 && y % 100 != 0) || y % 400 == 0. Test it on 1900 (no), 2000 (yes), 2100 (no), 2004 (yes) before trusting it.

Hint 3 — Difference, not two near-misses

Beginners often try to walk from date1 to date2 month by month, handling month-ends by hand. That path has five off-by-one opportunities. The serial-number design removes them all: convert both dates, subtract, done — and the same serial numbers later answer "what weekday is this?" for free.

Solution (try it first!)
#include <iostream>
using namespace std;

bool isLeap(int y) {
    return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}

int monthDays(int y, int m) {
    int d[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (m == 2 && isLeap(y)) return 29;
    return d[m];
}

long long serial(int y, int m, int d) {
    long long s = 0;
    for (int yy = 1900; yy < y; yy++) s += isLeap(yy) ? 366 : 365;
    for (int mm = 1; mm < m; mm++) s += monthDays(y, mm);
    return s + d;
}

int main() {
    int y1, m1, d1, y2, m2, d2;
    cin >> y1 >> m1 >> d1 >> y2 >> m2 >> d2;
    cout << serial(y2, m2, d2) - serial(y1, m1, d1) << endl;
    return 0;
}

The serial-number trick is one of the oldest ideas in computing — Unix timestamps are exactly this, counted in seconds since 1970. Everything you built here (epoch, month table, leap rule) transfers: add a weekday calculation (serial % 7), add time zones, and you have a date library's skeleton. The rules themselves are old friends from Leap Year — this problem is where they start earning money.

Deep dive

Why this works

Give every date a serial number — days since a fixed epoch — and differences become subtraction. The serial is built in three boring layers (whole years, whole months, day of month), each a small loop; all calendar ugliness lives inside the conversion where it can be tested once, instead of being smeared across the difference logic.

The cost

O(years) per conversion with the loop version — 200 iterations for the 1900–2100 range — and O(1) for the final subtraction. Constant-time versions exist (a formula with leap corrections), but the loop is provably right and fast enough.

Where it goes wrong

  • The century rule: 1900 and 2100 are NOT leap years (÷100 but not ÷400), 2000 IS. Testing only with 2000 hides the bug forever.
  • February's length must consult isLeap of the current year inside monthDays — a fixed 28/29 table keyed by month alone fails in leap years.
  • Inclusive counting: from a date to itself the answer is 0, and from Feb 28 to Mar 1 it is 1 in common years. Off-by-one here doubles or halves whole answers.

Next step

The leap rules come from Leap Year; the serial-number trick is Unix time in miniature — add serial % 7 and you get weekdays for free.

Two things to remember

  • Serial numbers turn date arithmetic into subtraction — convert, subtract, done.
  • Leap rule in one line: (y%4==0 && y%100!=0) || y%400==0 — test it on 1900, 2000, 2100.
🐞 This version fails — open it and try

Leap test is y % 4 == 0 only — 1900 and 2100 pass as leap years

#include <iostream>
using namespace std;

bool isLeap(int y) {
    return y % 4 == 0;   // bug: century rule missing
}

int monthDays(int y, int m) {
    int d[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (m == 2 && isLeap(y)) return 29;
    return d[m];
}

long long serial(int y, int m, int d) {
    long long s = 0;
    for (int yy = 1900; yy < y; yy++) s += isLeap(yy) ? 366 : 365;
    for (int mm = 1; mm < m; mm++) s += monthDays(y, mm);
    return s + d;
}

int main() {
    int y1, m1, d1, y2, m2, d2;
    cin >> y1 >> m1 >> d1 >> y2 >> m2 >> d2;
    cout << serial(y2, m2, d2) - serial(y1, m1, d1) << endl;
    return 0;
}