#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <sstream>
#include <format>
/**
* Generates all dates between start_date and end_date inclusive.
* Uses C++20 <chrono> and <format> for robust, calendar-aware date math.
*
* @param start_date_str Start date in "YYYY-MM-DD" format.
* @param end_date_str End date in "YYYY-MM-DD" format.
* @return std::vector<std::string> List of dates in "YYYY-MM-DD" format.
*/
std::vector<std::string> get_dates_between(const std::string& start_date_str, const std::string& end_date_str) {
namespace chrono = std::chrono;
std::vector<std::string> dates;
int start_y = 0, start_m = 0, start_d = 0;
int end_y = 0, end_m = 0, end_d = 0;
char dash1, dash2;
// 1. Parse input strings safely using string streams
std::istringstream start_stream(start_date_str);
if (!(start_stream >> start_y >> dash1 >> start_m >> dash2 >> start_d) || dash1 != '-' || dash2 != '-') {
std::cerr << "Error: Invalid start date format. Use YYYY-MM-DD.\n";
return {};
}
std::istringstream end_stream(end_date_str);
if (!(end_stream >> end_y >> dash1 >> end_m >> dash2 >> end_d) || dash1 != '-' || dash2 != '-') {
std::cerr << "Error: Invalid end date format. Use YYYY-MM-DD.\n";
return {};
}
// 2. Construct C++20 year_month_day objects
chrono::year_month_day start_ymd{chrono::year{start_y}, chrono::month{static_cast<unsigned>(start_m)}, chrono::day{static_cast<unsigned>(start_d)}};
chrono::year_month_day end_ymd{chrono::year{end_y}, chrono::month{static_cast<unsigned>(end_m)}, chrono::day{static_cast<unsigned>(end_d)}};
// Validate that the dates are valid calendar dates (e.g., checks for invalid days like Feb 31)
if (!start_ymd.ok() || !end_ymd.ok()) {
std::cerr << "Error: One or more dates are invalid calendar dates.\n";
return {};
}
// Convert to sys_days (duration since epoch in days) for safe arithmetic and comparison
chrono::sys_days current_date = chrono::sys_days{start_ymd};
chrono::sys_days final_date = chrono::sys_days{end_ymd};
if (current_date > final_date) {
std::cerr << "Error: Start date cannot be after the end date.\n";
return {};
}
// 3. Iterate day-by-day safely
while (current_date <= final_date) {
// Convert back to year_month_day for formatting
chrono::year_month_day ymd{current_date};
// Format using C++20 <format>
dates.push_back(std::format("{:%Y-%m-%d}", ymd));
// Increment by exactly 1 calendar day
current_date += chrono::days(1);
}
return dates;
}
int main() {
// Example usage spanning a month boundary and leap year
std::string start = "2026-02-26";
std::string end = "2026-03-02";
std::vector<std::string> dates = get_dates_between(start, end);
std::cout << "Dates between " << start << " and " << end << ":\n";
for (const auto& date : dates) {
std::cout << date << "\n";
}
}
/*
run:
Dates between 2026-02-26 and 2026-03-02:
2026-02-26
2026-02-27
2026-02-28
2026-03-01
2026-03-02
*/