从 C++ 中的给定日期(从头开始)减去天数

发布于 2025-01-14 12:11:01 字数 2129 浏览 0 评论 0原文

我有一个下面的函数,用于向给定日期添加天数(格式:yyyy/mm/dd addDays)。它不适用于闰年(有一次仓促的失败尝试使闰年起作用。)我如何编辑它以便我可以从给定日期中减去天数?我想我需要一个 for 循环,它也从 addDays_ 中减去天数,但会减少并重置。我还想让它成功计算闰年日期。

int year;
int month;
int day;
int changeDays;

void DaysToDate::add(int addDays_) {
    //Calculate the date add the changeDays.
    // Do NOT input values greater than 730 days.

    int monthdays[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
    int daysInYear = 365;
    
    if (isLeapYear(year) || isLeapYear(year+1) == true) {
        monthdays[2] = 29;
        daysInYear = 366;
        
    }

    if (addDays_ >= daysInYear) {
        int addyears = addDays_ / daysInYear;
        year += addyears;

        if (isLeapYear(year) == true) {
            
            monthdays[2] = 29;
            daysInYear = 366;
        }
    }


    int currentDays = day;
    int i = month;
    if (addDays_ >= monthdays[month]) {
        while (addDays_ >= monthdays[i]) {

            if (i + 1 >= 12) {
                month = 1;
                i = 1;
            }
            else 
                month++;

            addDays_ -= monthdays[i];

            //cout << "monthdays[i] "<< monthdays[i] << "\n";
            if (addDays_ + day < monthdays[month]) {
                day += addDays_;
            }
            i++;
        }
    }
    if (addDays_ + day < monthdays[month]) {
        day += addDays_;
    }
    if ((day == monthdays[month - 1]) && (month < 12))
    {
        day = 1;
        month++;
    }
    if ((day == monthdays[month - 1]) && (month == 12))
    {
        day = 1;
        month = 1;
        year++;
    }
    else {
        
    }

    cout << year << " " << month << " " << day << " " << "\n";

}

bool DaysToDate::isLeapYear(int year_) {
    if (year % 400 == 0) {
        return true;
    }

    if (year % 100 == 0) {
        return false;
    }

    if (year % 4 == 0) {
        return true;
    }

    else {
        return false;
    }
    
}

输入 2009/04/05 7 - 输出 2009 4 12

I have a function below used to add a number of days to a given date (format: yyyy/mm/dd addDays). It does not work for leap years (there was a rushed failed attempt to make leap years work.) How can I edit this so I may subtract days from a given date? I imagine I will need a for loop which also subtracts days from addDays_ but with a decrement and reset. I'd also like to make it calculate leap year dates successfully.

int year;
int month;
int day;
int changeDays;

void DaysToDate::add(int addDays_) {
    //Calculate the date add the changeDays.
    // Do NOT input values greater than 730 days.

    int monthdays[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
    int daysInYear = 365;
    
    if (isLeapYear(year) || isLeapYear(year+1) == true) {
        monthdays[2] = 29;
        daysInYear = 366;
        
    }

    if (addDays_ >= daysInYear) {
        int addyears = addDays_ / daysInYear;
        year += addyears;

        if (isLeapYear(year) == true) {
            
            monthdays[2] = 29;
            daysInYear = 366;
        }
    }


    int currentDays = day;
    int i = month;
    if (addDays_ >= monthdays[month]) {
        while (addDays_ >= monthdays[i]) {

            if (i + 1 >= 12) {
                month = 1;
                i = 1;
            }
            else 
                month++;

            addDays_ -= monthdays[i];

            //cout << "monthdays[i] "<< monthdays[i] << "\n";
            if (addDays_ + day < monthdays[month]) {
                day += addDays_;
            }
            i++;
        }
    }
    if (addDays_ + day < monthdays[month]) {
        day += addDays_;
    }
    if ((day == monthdays[month - 1]) && (month < 12))
    {
        day = 1;
        month++;
    }
    if ((day == monthdays[month - 1]) && (month == 12))
    {
        day = 1;
        month = 1;
        year++;
    }
    else {
        
    }

    cout << year << " " << month << " " << day << " " << "\n";

}

bool DaysToDate::isLeapYear(int year_) {
    if (year % 400 == 0) {
        return true;
    }

    if (year % 100 == 0) {
        return false;
    }

    if (year % 4 == 0) {
        return true;
    }

    else {
        return false;
    }
    
}

Input 2009/04/05 7 - output 2009 4 12

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

残月升风 2025-01-21 12:11:01

为了修复代码以在闰年工作:

#include <iostream>

int year = 2009;
int month = 02;
int day = 1;
int changeDays;

enum Months
{
    None,
    January,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December
};

bool isLeapYear(int year_)
{
    if (year % 400 == 0)
    {
        return true;
    }

    if (year % 100 == 0)
    {
        return false;
    }

    if (year % 4 == 0)
    {
        return true;
    }

    else
    {
        return false;
    }
}

void add(int addDays_)
{
    // Calculate the date add the changeDays.
    //  Do NOT input values greater than 730 days.

    int monthdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int daysInYear = 365;

    if (isLeapYear(year))
    {
        monthdays[Months::February] = 29;
        daysInYear = 366;
    }

    int currentDays = day;
    int i = month;

    while (addDays_ >= monthdays[i])
    {
        addDays_ -= monthdays[i];
        
        if (i + 1 > Months::December)
        {
            i = Months::January;
            year++;
            if (isLeapYear(year))
            {
                monthdays[Months::February] = 29;
                daysInYear = 366;
            } else {
                monthdays[Months::February] = 28;
                daysInYear = 365;
            }
        }
        else
        {
            i++;
        }

    }
    month = i;

    if (addDays_ + day <= monthdays[month])
    {
        day += addDays_;
    }
    else if (month < Months::December) {
        addDays_ -= monthdays[month] - day;
        day = addDays_;
        month++;
    } else {
        addDays_ -= monthdays[month] - day;
        day = addDays_;
        month = Months::January;
        year ++;
        if (isLeapYear(year))
        {
            monthdays[Months::February] = 29;
            daysInYear = 366;
        } else {
            monthdays[Months::February] = 28;
            daysInYear = 365;
        }
    }

    std::cout << year << " " << month << " " << day << " "
         << "\n";
}


int main(int argc, char const *argv[])
{
    add(7);
    add(365);
    add(365);
    add(365);
    add(365);
    return 0;
}

当然可以对我的建议进行一些改进,但我认为它很容易遵循,因为它的结构与您的非常相似。

作为一般提示,您有很多冗余的 if 语句,其中一些会导致错误,例如

if (isLeapYear(year) || isLeapYear(year+1) == true) {
    monthdays[2] = 29;
    daysInYear = 366;  
}

如果您在三月之前开始,检查 isLeapYear(year+1) 会得到错误的天数

For fixing the code to work on leap years:

#include <iostream>

int year = 2009;
int month = 02;
int day = 1;
int changeDays;

enum Months
{
    None,
    January,
    February,
    March,
    April,
    May,
    June,
    July,
    August,
    September,
    October,
    November,
    December
};

bool isLeapYear(int year_)
{
    if (year % 400 == 0)
    {
        return true;
    }

    if (year % 100 == 0)
    {
        return false;
    }

    if (year % 4 == 0)
    {
        return true;
    }

    else
    {
        return false;
    }
}

void add(int addDays_)
{
    // Calculate the date add the changeDays.
    //  Do NOT input values greater than 730 days.

    int monthdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int daysInYear = 365;

    if (isLeapYear(year))
    {
        monthdays[Months::February] = 29;
        daysInYear = 366;
    }

    int currentDays = day;
    int i = month;

    while (addDays_ >= monthdays[i])
    {
        addDays_ -= monthdays[i];
        
        if (i + 1 > Months::December)
        {
            i = Months::January;
            year++;
            if (isLeapYear(year))
            {
                monthdays[Months::February] = 29;
                daysInYear = 366;
            } else {
                monthdays[Months::February] = 28;
                daysInYear = 365;
            }
        }
        else
        {
            i++;
        }

    }
    month = i;

    if (addDays_ + day <= monthdays[month])
    {
        day += addDays_;
    }
    else if (month < Months::December) {
        addDays_ -= monthdays[month] - day;
        day = addDays_;
        month++;
    } else {
        addDays_ -= monthdays[month] - day;
        day = addDays_;
        month = Months::January;
        year ++;
        if (isLeapYear(year))
        {
            monthdays[Months::February] = 29;
            daysInYear = 366;
        } else {
            monthdays[Months::February] = 28;
            daysInYear = 365;
        }
    }

    std::cout << year << " " << month << " " << day << " "
         << "\n";
}


int main(int argc, char const *argv[])
{
    add(7);
    add(365);
    add(365);
    add(365);
    add(365);
    return 0;
}

Surely some improvements can be done to my suggestion but I think it is easy to follow, as it has a very similar structure to yours.

As a general tip, you had a lot of redundant if statements and some of them would cause errors, such as

if (isLeapYear(year) || isLeapYear(year+1) == true) {
    monthdays[2] = 29;
    daysInYear = 366;  
}

checking isLeapYear(year+1) will get you a wrong number of days if you start before march

终止放荡 2025-01-21 12:11:01

您可以为此使用范围。将给定日期 ymd 添加(或减去)天数 n 的操作可以视为:

  • 生成当前日期 ymd< 的视图/code> 加上以下日期(最多 730 个)。
  • 从该视图中,删除前 n 个元素。
  • 然后取剩下的第一个元素。

ranges::views::generate_n 代码将包含向给定日期添加(或减去)一天的逻辑:

  • 此逻辑将使用 days_per_month 函数。
  • days_per_month 函数将使用 is_leap_year 函数。

下面的代码:

  • 定义一个 struct ymd 来保存给定日期的值。
  • 作为 struct ymd 的非成员运算符实现给定日期的天数加法和减法。
  • 使用 Eric Niebler 的 Range-v3 库进行范围操作。

[演示]

#include <cassert>  // assert
#include <iomanip>  // setw
#include <iostream>  // cout
#include <fmt/core.h>
#include <range/v3/all.hpp>
#include <utility>
#include <vector>

struct ymd {
    int year{};
    int month{};
    int day{};
};

auto is_leap_year(int y) {
    return (y % 4 == 0) and ((y % 100 != 0) or (y % 400 == 0));
}

auto days_per_month(int y, int m) {
    static int dpm[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (m == 2 and is_leap_year(y)) { return 29; }
    else { return dpm[m]; }
}

auto operator+(const ymd& d, int days_to_add) {
    static const int max_days_to_add{730};
    assert(days_to_add <= max_days_to_add);
    auto ret_v =
        ranges::views::generate_n([dd=d]() mutable -> ymd {
            auto tmp{dd};
            dd.day += 1;
            if (dd.day > days_per_month(dd.year, dd.month)) { dd.day = 1; dd.month += 1; }
            if (dd.month > 12) { dd.month = 1; dd.year += 1; }
            return tmp;
        }, max_days_to_add + 1)
        | ranges::views::drop(days_to_add)
        | ranges::views::take(1)
        | ranges::to<std::vector>();
    return ret_v[0];
}

auto operator+(int days_to_add, const ymd& d) {
    return d + days_to_add;
}

auto operator-(const ymd& d, int days_to_subtract) {
    static const int max_days_to_subtract{730};
    assert(days_to_subtract <= max_days_to_subtract);
    auto ret_v =
        ranges::views::generate_n([dd=d]() mutable -> ymd {
            auto tmp{dd};
            dd.day -= 1;
            if (dd.day < 1) {
                dd.month -= 1;
                if (dd.month < 1) { dd.month = 12; dd.year -= 1; }
                dd.day = days_per_month(dd.year, dd.month);
            }
            return tmp;
        }, max_days_to_subtract + 1)
        | ranges::views::drop(days_to_subtract)
        | ranges::views::take(1)
        | ranges::to<std::vector>();
    return ret_v[0];
}

std::ostream& operator<<(std::ostream& os, const ymd& d) {
    return os << fmt::format("{:04d}/{:02d}/{:02d}", d.year, d.month, d.day);
}

int main() {
    std::vector<std::pair<ymd,int>> input{
        {{2009,4,5}, 7},
        {{2009,4,5}, 730},
        {{2020,2,20}, 30}
    };
    for (const auto& [d, number_of_days] : input){
        auto dd{ d + number_of_days };
        std::cout << d << " + " << std::setw(3) << number_of_days << " = " << dd << ",\t";
        std::cout << dd << " - " << std::setw(3) << number_of_days << " = " << dd - number_of_days << "\n";
    }
}

// Outputs:
//   2009/04/05 +   7 = 2009/04/12, 2009/04/12 -   7 = 2009/04/05
//   2009/04/05 + 730 = 2011/04/05, 2011/04/05 - 730 = 2009/04/05
//   2020/02/20 +  30 = 2020/03/21, 2020/03/21 -  30 = 2020/02/20

另一个可能更简单的解决方案是循环,直到消耗完要添加的天数,递增当前日期,直到下个月月初或直到用完要添加的天数(或者如果要减去,则递减直到上个月月底)。再次,我将使用 daysPerMonthisLeapYear 辅助函数:

[演示]

    void add(int addDays) {
        static int maxAddDays = 730;
        assert(addDays <= maxAddDays);

        while (addDays) {
            auto current_month_days(daysPerMonth(year_, month_));
            auto tmpAddDays = std::min(addDays, current_month_days - day_ + 1);
            day_ += tmpAddDays;
            addDays -= tmpAddDays;
            if (day_ == current_month_days + 1) { day_ = 1; month_++; }
            if (month_ == 13) { month_ = 1; year_++; }
        }
    }

    void subtract(int subtractDays) {
        static int maxSubtractDays = 730;
        assert(subtractDays <= maxSubtractDays);

        while (subtractDays) {
            auto tmpSubtractDays = std::min(subtractDays, day_);
            day_ -= tmpSubtractDays;
            subtractDays -= tmpSubtractDays;
            if (day_ == 0) {
                month_--;
                if (month_ == 0) { month_ = 12; year_--; }
                day_ = daysPerMonth(year_, month_);
            }
        }
    }

You could use ranges for this. The operation of adding (or subtracting) a number of days n to a given date ymd may be then thought as:

  • Generate a view of the current date ymd plus the following dates (a maximum of 730).
  • From that view, drop the first n elements.
  • Then take the first element of the remaining.

The ranges::views::generate_n code will contain the logic for adding (or subtracting) a day to a given date:

  • This logic will make use of the days_per_month function.
  • The days_per_month function will make use of the is_leap_year function.

The code below:

  • Defines a struct ymd to hold the values of a given date.
  • Implements the addition and subtraction of days to a given date as non member operators of the struct ymd.
  • Uses Eric Niebler's Range-v3 library for the range operations.

[Demo]

#include <cassert>  // assert
#include <iomanip>  // setw
#include <iostream>  // cout
#include <fmt/core.h>
#include <range/v3/all.hpp>
#include <utility>
#include <vector>

struct ymd {
    int year{};
    int month{};
    int day{};
};

auto is_leap_year(int y) {
    return (y % 4 == 0) and ((y % 100 != 0) or (y % 400 == 0));
}

auto days_per_month(int y, int m) {
    static int dpm[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (m == 2 and is_leap_year(y)) { return 29; }
    else { return dpm[m]; }
}

auto operator+(const ymd& d, int days_to_add) {
    static const int max_days_to_add{730};
    assert(days_to_add <= max_days_to_add);
    auto ret_v =
        ranges::views::generate_n([dd=d]() mutable -> ymd {
            auto tmp{dd};
            dd.day += 1;
            if (dd.day > days_per_month(dd.year, dd.month)) { dd.day = 1; dd.month += 1; }
            if (dd.month > 12) { dd.month = 1; dd.year += 1; }
            return tmp;
        }, max_days_to_add + 1)
        | ranges::views::drop(days_to_add)
        | ranges::views::take(1)
        | ranges::to<std::vector>();
    return ret_v[0];
}

auto operator+(int days_to_add, const ymd& d) {
    return d + days_to_add;
}

auto operator-(const ymd& d, int days_to_subtract) {
    static const int max_days_to_subtract{730};
    assert(days_to_subtract <= max_days_to_subtract);
    auto ret_v =
        ranges::views::generate_n([dd=d]() mutable -> ymd {
            auto tmp{dd};
            dd.day -= 1;
            if (dd.day < 1) {
                dd.month -= 1;
                if (dd.month < 1) { dd.month = 12; dd.year -= 1; }
                dd.day = days_per_month(dd.year, dd.month);
            }
            return tmp;
        }, max_days_to_subtract + 1)
        | ranges::views::drop(days_to_subtract)
        | ranges::views::take(1)
        | ranges::to<std::vector>();
    return ret_v[0];
}

std::ostream& operator<<(std::ostream& os, const ymd& d) {
    return os << fmt::format("{:04d}/{:02d}/{:02d}", d.year, d.month, d.day);
}

int main() {
    std::vector<std::pair<ymd,int>> input{
        {{2009,4,5}, 7},
        {{2009,4,5}, 730},
        {{2020,2,20}, 30}
    };
    for (const auto& [d, number_of_days] : input){
        auto dd{ d + number_of_days };
        std::cout << d << " + " << std::setw(3) << number_of_days << " = " << dd << ",\t";
        std::cout << dd << " - " << std::setw(3) << number_of_days << " = " << dd - number_of_days << "\n";
    }
}

// Outputs:
//   2009/04/05 +   7 = 2009/04/12, 2009/04/12 -   7 = 2009/04/05
//   2009/04/05 + 730 = 2011/04/05, 2011/04/05 - 730 = 2009/04/05
//   2020/02/20 +  30 = 2020/03/21, 2020/03/21 -  30 = 2020/02/20

Another, probably simpler, solution would be to loop until you consume the days you want to add, incrementing the current day whether until the beginning of the next month or until you run out of days to add (or decrementing until the end of the previous month if you are subtracting). Again, I would make use of daysPerMonth and isLeapYear helper functions:

[Demo]

    void add(int addDays) {
        static int maxAddDays = 730;
        assert(addDays <= maxAddDays);

        while (addDays) {
            auto current_month_days(daysPerMonth(year_, month_));
            auto tmpAddDays = std::min(addDays, current_month_days - day_ + 1);
            day_ += tmpAddDays;
            addDays -= tmpAddDays;
            if (day_ == current_month_days + 1) { day_ = 1; month_++; }
            if (month_ == 13) { month_ = 1; year_++; }
        }
    }

    void subtract(int subtractDays) {
        static int maxSubtractDays = 730;
        assert(subtractDays <= maxSubtractDays);

        while (subtractDays) {
            auto tmpSubtractDays = std::min(subtractDays, day_);
            day_ -= tmpSubtractDays;
            subtractDays -= tmpSubtractDays;
            if (day_ == 0) {
                month_--;
                if (month_ == 0) { month_ = 12; year_--; }
                day_ = daysPerMonth(year_, month_);
            }
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文