C++ Calendar Generator Project
Print a correctly aligned calendar for any month and year.
What you will build
Type a month and year, get a neat wall-calendar grid. The puzzle is calendrical: you must work out which weekday the 1st falls on (leap years included) and pad the first row. It's pure logic and formatting — no libraries doing the work for you.
What you will learn
- Leap-year rules and days-in-month tables
- Computing a weekday from a date (e.g. Zeller's congruence)
- Nested loops for grid layout
- Precise column formatting with setw
Feature checklist
- Correct calendars for any month/year
- Leap years handled (Feb has 29 days)
- Week starts on Sunday or Monday (your choice)
- Aligned columns with weekday headers
- Option to print a whole year
Starter code
#include <iostream>
#include <iomanip>
bool isLeap(int y) { return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; }
int daysInMonth(int m, int y) {
static const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
return (m == 2 && isLeap(y)) ? 29 : days[m - 1];
}
// Zeller's congruence: 0 = Saturday ... 6 = Friday
int firstWeekday(int m, int y) {
if (m < 3) { m += 12; --y; }
int k = y % 100, j = y / 100;
int h = (1 + 13 * (m + 1) / 5 + k + k / 4 + j / 4 + 5 * j) % 7;
return (h + 6) % 7; // convert so 0 = Sunday
}
int main() {
int m = 10, y = 2026;
int start = firstWeekday(m, y);
std::cout << " Su Mo Tu We Th Fr Sa\n";
for (int i = 0; i < start; ++i) std::cout << " ";
for (int d = 1; d <= daysInMonth(m, y); ++d) {
std::cout << std::setw(3) << d;
if ((start + d) % 7 == 0) std::cout << "\n";
}
std::cout << "\n";
}Full walkthrough
Step 1: Write isLeap() — the rule everything depends on
A year is a leap year if it is divisible by 4, except century years, which must be divisible by 400: (y % 4 == 0 && y % 100 != 0) || y % 400 == 0. So 2024 is a leap year, 1900 was not, 2000 was. Get this one line wrong and every February you ever print is wrong.
Step 2: Build daysInMonth() on top of it
A static table {31,28,31,30,31,30,31,31,30,31,30,31} answers every month except February in a leap year, which returns 29. Taking the year as a parameter (not just the month) is the whole point — daysInMonth(2, 2024) and daysInMonth(2, 2023) must be able to disagree.
int daysInMonth(int m, int y) {
static const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
return (m == 2 && isLeap(y)) ? 29 : days[m - 1];
}Step 3: Find the weekday of the 1st with Zeller's congruence
firstWeekday(m, y) uses Zeller's formula: January and February are counted as months 13 and 14 of the PREVIOUS year (that is why the code does m += 12 and --y), then a mix of divisions by 4 and 100 extracts the weekday. The starter converts Zeller's Saturday-first result with (h + 6) % 7 so 0 = Sunday, matching the printed header.
Step 4: Print the header and the leading blanks
Print ' Su Mo Tu We Th Fr Sa' then start empty cells: for (i = 0; i < start; ++i) print three spaces each. Those blanks are what push the 1st under the correct weekday column. Every column is exactly 3 characters wide — that fixed width is the entire layout system.
Step 5: Print the days with setw and wrap weekly
Each day prints with std::setw(3) from <iomanip>. After printing day d, if (start + d) % 7 == 0 the week is complete, so print a newline. Notice the wrap test uses start + d — the day's position in the grid — not just d % 7; forgetting the start offset misaligns every row after the first.
for (int d = 1; d <= daysInMonth(m, y); ++d) {
std::cout << std::setw(3) << d;
if ((start + d) % 7 == 0) std::cout << "\n";
}Step 6: Let the user choose month and year
The starter hard-codes October 2026 so you can verify the layout; the finished program prompts for month and year and validates 1–12 for the month. Verify October 2026 by hand: the 1st is a Thursday, so four blank cells precede it, and the month has 31 days.
Step 7: Add the whole-year view
For the checklist's year option, loop m from 1 to 12, print the month name above each grid, and reuse the exact same printing code — if you copied the code instead of calling it, this is your sign to refactor it into a printMonth(m, y) function first.
Common mistakes
- Forgetting the start offset in the wrap test, so only the first row is aligned and the rest drift.
- Feeding January/February into Zeller without converting them to months 13/14 of the previous year — every winter month lands on the wrong weekday.
- A days table indexed by m instead of m - 1, shifting every month's length by one.
Compile and run
g++ -std=c++17 -o calendar calendar.cppSample run
$ ./calendar
Month (1-12):
> 10
Year:
> 2026
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
$ ./calendar
Month (1-12):
> 2
Year:
> 2024
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29Try it in your browser
No browser demo is included for this project. Build the C++ version below — that is the real program.