C++ 在C+中同时使用月份和日期+;

C++ 在C+中同时使用月份和日期+;,c++,date,C++,Date,我试图制作一个计算游泳池会员费的程序。用户将输入一个日期(会员最后一次更新会员资格的时间),程序将使用当前日期计算其会员资格是否过期 会员资格将在一年后加入的月份开始前一周(或另一个任意时间段)过期。例如,如果我在2016年2月加入,我必须在2017年1月24日或之前付款,以确保会员资格过期。一到1月25日,应收取一个月的费用(15美元),一到2月25日,应收取两个月的费用等 然而,我不知道如何收费后的几个月,第一次。例如,2月3日付款应导致逾期一个月,但2月26日付款应为两个月,但我不知道如何

我试图制作一个计算游泳池会员费的程序。用户将输入一个日期(会员最后一次更新会员资格的时间),程序将使用当前日期计算其会员资格是否过期

会员资格将在一年后加入的月份开始前一周(或另一个任意时间段)过期。例如,如果我在2016年2月加入,我必须在2017年1月24日或之前付款,以确保会员资格过期。一到1月25日,应收取一个月的费用(15美元),一到2月25日,应收取两个月的费用等

然而,我不知道如何收费后的几个月,第一次。例如,2月3日付款应导致逾期一个月,但2月26日付款应为两个月,但我不知道如何做到这一点

我如何修复我的函数,因为它似乎不工作? 例如,我已于2016年11月15日入会,由于会员资格于2017年10月24日到期,因此应返回15,但返回0

int membershipFine(int joinDay, int joinMonth, int joinYear, int currentDay, int currentMonth, int currentYear)
{
    int dueDay[12] = {25, 22, 25, 24, 25, 24, 25, 25, 24, 25, 24, 25}; // the week before the end of each month in days
    int correspondingMonth = joinMonth - 2; // finds the element position that corresponds
    if (correspondingMonth == -1) // if they joined in january, the array will go to december
    {
        correspondingMonth = 11;
    }
    int differenceInMonths = currentMonth - joinMonth + 12 * (currentYear - joinYear);
    if (differenceInMonths < 11)
    {
        return 0;
    }
    else if ((differenceInMonths == 11) && (joinDay < dueDay[correspondingMonth]))
    {
        return 0;
    }
    else if (differenceInMonths == 11)
    {
        return 15;
    }

    if (differenceInMonths > 11 && joinDay < dueDay[correspondingMonth]) // not sure about this if and else statement
    {
        return (differenceInMonths - 11) * 15;
    }
    else return (differenceInMonths - 10) * 15;
}     
int会员资格罚款(int joinDay、int joinMonth、int joinYear、int currentDay、int currentMonth、int currentYear)
{
int dueDay[12]={25,22,25,24,25,25,24,24,25,25,24,25};//每个月结束前的一周,以天为单位
int correspondingmount=joinMonth-2;//查找对应的元素位置
if(correspondingmount==-1)//如果他们在一月加入,数组将转到十二月
{
相应月份=11;
}
int DifferenceInMonth=currentMonth-joinMonth+12*(currentYear-joinYear);
if(差分数<11)
{
返回0;
}
否则如果((差分月数==11)和((联合日<联合日[对应月])
{
返回0;
}
else if(differenceimonths==11)
{
返回15;
}
if(differenceimonths>11&&joinDay处理日期和时间的最佳方法是使用一个库,将整数的抽象级别提高到日期和时间。是这样一种工具

它有一个名为
date::year\u month\u day
{year,month,day}
类,用于年和月算术。您可以使用它将
membershipFine
的API从接受6个类型不安全参数更改为仅接受两个类型安全参数:

int
membershipFine(date::year_month_day joinDate, date::year_month_day currentDate);
您对到期日的描述似乎表明,到期日与加入日期当月的日期无关,并且到期日为1年,从加入日期当月的第一天算起不到1周。如果这是真的,可以很容易地这样计算:

using namespace date;
year_month_day dueDate{
    local_days{(joinDate.year()/joinDate.month() + years{1})/1} - weeks{1}};
std::cout << membershipFine(join, today) << '\n';
表达式
joinDate.year()/joinDate.month()
创建一个
year\u month
对象,该对象仅为一年和一个月,忽略了
joinDate
中的月份。我在该
年/月
的基础上加上1年,这会导致另一个
年/月
,正好是1年后

在这个总数中,附加了
/1
。这将创建一个与上述
年月
月份的第一天相对应的
年月

现在,尽管
year\u month\u day
对于面向
year
month
的算法来说是很好的,但是对于面向日和周的算法来说却不是很好。最好的数据结构是某个时代的
{countofdays}
。这个库有一个名为
local\u days
的数据结构。所以我转换成,减去1周,然后转换回
年\月\日

所有这些(计算到期日)都发生在上面的代码行中

现在我需要根据
currentDate
dueDate
之间的关系来计算
fine
。如果
currentDate
,则
罚款为0美元,否则为整月数的函数(加1)
currentDate
超过
dueDate
(我理解您的问题陈述):

可以通过转换为
year\u month
对象并进行减法来计算月差(忽略月的哪一天)。现在如果
currentDate.day()
,这就是正确答案。例如,如果月差为1,但
currentDate
中的月日尚未超过
dueDate
中的月日,则我们不想收取第二个月的费用,否则我们会收取。如果我们这样做,
differenceimonths
将递增

然后,
fine
就是
differenceinmonts
,从
months
转换为整数,乘以15

如果有任何
风扇,则
差异月数的类型实际上是一个
std::chrono::duration
,其周期正好是平均月。因此,
.count()
成员函数可以访问基础的整数值

我在上面的代码中添加了一些print语句,下面我用几个示例展示了整个过程以及一个驱动程序:

#include "date/date.h"
#include <iostream>

int
membershipFine(date::year_month_day joinDate, date::year_month_day currentDate)
{
    using namespace date;
    year_month_day dueDate{
        local_days{(joinDate.year()/joinDate.month() + years{1})/1} - weeks{1}};
    int fine = 0;
    if (currentDate >= dueDate)
    {
        auto differenceInMonths = currentDate.year()/currentDate.month() -
                                  dueDate.year()/dueDate.month();
        if (currentDate.day() >= dueDate.day())
            ++differenceInMonths;
        fine = differenceInMonths.count() * 15;
    }
    std::cout << "join    Date is " << joinDate << '\n';
    std::cout << "due     Date is " << dueDate << '\n';
    std::cout << "current Date is " << currentDate << '\n';
    std::cout << "fine is         $" << fine << '\n';
    return fine;
}

int
main()
{
    using namespace date::literals;
    std::cout << membershipFine(feb/29/2016, jan/24/2017) << '\n';
    std::cout << membershipFine(feb/29/2016, jan/25/2017) << '\n';
    std::cout << membershipFine(feb/29/2016, feb/24/2017) << '\n';
    std::cout << membershipFine(feb/29/2016, feb/25/2017) << '\n';
}
总之,使用这样的库可以让您不必考虑
int
s,因此您可以专注于必须实现的日期和日历逻辑。结果是代码紧凑易读,更有可能是正确的

更新

在下面的评论中,OP询问如何从
cin
解析日期以及如何获取当前日期。有几种选择

以下是我建议的约会方式:

date::year_month_day join;
while (true)
{
    std::cout << "Enter join date as yyyy-mm-dd: ";
    std::cin >> date::parse("%F", join);
    if (!std::cin.fail())
        break;
    std::cin.clear();
    std::string garbage;
    std::getline(std::cin, garbage);
    std::cout << "Please try again.\n";
}
如果希望当前日期位于当前本地时间z以外的某个时区
date::year_month_day join;
while (true)
{
    std::cout << "Enter join date as yyyy-mm-dd: ";
    std::cin >> date::parse("%F", join);
    if (!std::cin.fail())
        break;
    std::cin.clear();
    std::string garbage;
    std::getline(std::cin, garbage);
    std::cout << "Please try again.\n";
}
using namespace std::chrono;
using namespace date;
year_month_day today = floor<days>(system_clock::now());
year_month_day today{floor<days>(make_zoned(current_zone(),
                                            system_clock::now()).get_local_time())};
year_month_day today{floor<days>(make_zoned("America/Los_Angeles",
                                            system_clock::now()).get_local_time())};
std::cout << membershipFine(join, today) << '\n';