How to get all dates between 2 dates in C++

1 Answer

0 votes
#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

*/

 



answered 5 days ago by avibootz
...