How to Get the Weekday for Any Month and Year in C++
When building a calendar or date-picker utility in terminal-based C++, determining the exact day of the week (Monday through Sunday) for any given date is a fundamental requirement. If you are struggling with complex date arithmetic or wrestling with ctime, you are not alone.
In this guide, we will explore the best ways to determine weekdays in C++: the modern, effortless C++20 <chrono> approach, followed by the classic std::mktime solution for older standards.
The Problem with Calculating Date Differences
A common pitfall is fetching the current date via localtime() and attempting to calculate relative differences between the current year/month and the user's input. This approach quickly becomes brittle due to leap years, daylight saving time (DST), and varying month lengths.
Instead, the simplest approach is to populate a date structure directly with the target year, month, and day, then ask the standard library to resolve the day of the week.
Method 1: The Modern C++20 Way (Recommended)
C++20 introduced extensive calendar extensions to the <chrono> library. It is type-safe, eliminates manual conversions (like year - 1900), and handles leap years automatically.
#include <iostream>
#include <chrono>
#include <format> // Or use std::cout with older stream support
int main() {
int year_input = 2026;
int month_input = 10; // October
std::chrono::year y{year_input};
std::chrono::month m{static_cast<unsigned>(month_input)};
std::chrono::year_month ym{y, m};
// Get the last day of the month accurately (handles leap years)
std::chrono::year_month_day_last ymdl{y, std::chrono::month_day_last{m}};
unsigned int total_days = static_cast<unsigned>(ymdl.day());
std::cout << "Output: " << year_input << "-" << month_input << "\n";
for (unsigned int d = 1; d <= total_days; ++d) {
std::chrono::year_month_day ymd{y, m, std::chrono::day{d}};
std::chrono::weekday wd{std::chrono::sys_days{ymd}};
// Using std::format (C++20)
std::cout << d << " " << std::format("{:%A}", wd) << "\n";
}
return 0;
}Why this works:
std::chrono::sys_daysautomatically casts a date into a count of days since the Unix epoch.- Casting that back to
std::chrono::weekdaycomputes the correct weekday instantly. std::format("{:%A}", wd)prints the full weekday name (e.g., "Thursday"). Use"{%a}"for abbreviated names ("Thu").
Method 2: Using Classic C++ (<ctime> and mktime)
If your compiler doesn't support C++20 yet, you can fix your original code using std::mktime. When you populate a std::tm structure and call mktime, the library automatically calculates and populates the tm_wday field (where 0 = Sunday, 1 = Monday, etc.).
#include <iostream>
#include <ctime>
#include <vector>
#include <string>
const std::vector<std::string> WEEKDAYS = {
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
};
// Helper to determine the number of days in a month
int getDaysInMonth(int year, int month) {
if (month == 2) {
bool isLeap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
return isLeap ? 29 : 28;
}
if (month == 4 || month == 6 || month == 9 || month == 11) {
return 30;
}
return 31;
}
int main() {
int year = 2026;
int month = 10; // 1-based (1 = Jan, 10 = Oct)
int days = getDaysInMonth(year, month);
for (int day = 1; day <= days; ++day) {
std::tm date = {};
date.tm_year = year - 1900; // Years since 1900
date.tm_mon = month - 1; // Months since January (0-11)
date.tm_mday = day; // Day of the month (1-31)
date.tm_isdst = -1; // Let system determine DST
// mktime normalizes the struct and computes tm_wday
if (std::mktime(&date) != -1) {
std::cout << day << " " << WEEKDAYS[date.tm_wday] << "\n";
}
}
return 0;
}Important Details for std::tm:
tm_year: Counted as years since 1900 (e.g.,2026 - 1900 = 126).tm_mon: Zero-indexed (0 for January, 9 for October).tm_isdst: Always set to-1before callingmktime()so the C runtime determines whether Daylight Saving Time is in effect.
Summary
- Avoid computing manual date deltas against
time(nullptr). - If using C++20 or newer, prefer
std::chronodate types for a clean, type-safe API. - If using C++11 through C++17, populate a zero-initialized
std::tmstruct and invokestd::mktime()to obtaintm_wday.