2017-10-30 6 views
-2

私は、プールのメンバーシップの料金を計算するプログラムを作ろうとしていました。ユーザーは日付(メンバーが最後にメンバーシップを更新したとき)を入力し、現在の日付を使用してメンバーシップが期限切れになったかどうかを計算します。C++で月と日付を一緒に使用する

メンバーシップは、1年後に参加した月の開始前に1週間(または別の任意の期間)延期されることを意味します。たとえば、2016年2月に入会した場合、2017年1月24日以前に入会した場合、メンバーシップが遅れていることを確認する必要があります。 1月25日に到着するとすぐに月額料金が請求され(15ドル)、2月25日に到着すると2ヶ月料金が課金されます。

ただし、後で請求する方法はわかりません最初の1ヶ月後の数ヶ月。たとえば、2月3日の支払いは1ヶ月遅れとなりますが、2月26日の支払いは2ヶ月にする必要がありますが、これを行う方法はわかりません。

機能が動作していないと思われるため、どのように機能を修正できますか? など。日付と時刻に対処するための最良の方法は、のレベルを上げるのライブラリを使用することです私は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; 
}  
+0

:あなたのjointodayお尻、彼らはこのように使用することができます。また、実際のエラーまたは予期しない出力が何であるかを示します。宿題の一部で、あなたが求めている質問を理解することができます。 – MrJLP

答えて

1

を返します。整数についての抽象、日時への変換Howard Hinnant's free, open-source, header-only libraryはそのようなツールです。

{year, month, day}date::year_month_dayと呼ばれるクラスで、年と月の演算に適しています。

int 
membershipFine(date::year_month_day joinDate, date::year_month_day currentDate); 

期日のご説明は、それが一日とは無関係であることを言って表示されます。一つは、ちょうど2つのタイプセーフなパラメータする6種類の危険なパラメータを取ってからmembershipFineのAPIを変更するためにこれを使用することができます参加日の1ヶ月、参加日の月の初めから1週間少ない1年であることを確認します。これが本当であるならば、これは簡単にこのように計算することができます。

using namespace date; 
year_month_day dueDate{ 
    local_days{(joinDate.year()/joinDate.month() + years{1})/1} - weeks{1}}; 

表現joinDate.year()/joinDate.month()joinDateから日の-ヶ月を無視し、ちょうど一年と月ですyear_monthオブジェクトを作成します。私は1年をそのyear_monthに追加し、正確に1年後に別のyear_monthという結果になります。

その合計には、/1が追加されています。これにより、前述のyear_monthの月の初日に対応するyear_month_dayが作成されます。

year_month_dayは、yearmonthの指向の計算には適していますが、曜日と週指向の計算ではそれほど大きくありません。そのための最良のデータ構造は、ある時代の{count-of-days}です。このライブラリはlocal_daysというデータ構造を持っています。だから私はそれに変換し、1週間を引いた後、year_month_dayに戻って変換します。

これのすべて(期日を計算するため)は、上記のコード行で行われます。

currentDatedueDateの関係に基づいて、fineを計算する必要があります。finecurrentDate < dueDate場合、$ 0になり、それ以外の場合は全体の数ヶ月の数の関数である(プラス1)currentDateは(私はあなたの問題文を理解して)dueDateを超えています:

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; 
} 

ヶ月の違い、日無視します-of-the-monthは、year_monthオブジェクトに変換して減算することで計算できます。今、currentDate.day() < dueDate.day()の場合、これは正解です。たとえば、月の相違が1であるのに、currentDateの月の日がdueDateの月の日をまだ超えていない場合は、2か月間は請求したくありません。もしそうなら、differenceInMonthsがインクリメントされます。

その後fineは、単にdifferenceInMonthsあり、そこに任意の<chrono>ファンがある場合は、differenceInMonthsの種類は、実際に正確である期間とstd::chrono::durationで一体化し、回15

<aside>monthsから変換平均月。したがって、.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'; 
} 

この出力:

join Date is 2016-02-29 
due  Date is 2017-01-25 
current Date is 2017-01-24 
fine is   $0 
0 
join Date is 2016-02-29 
due  Date is 2017-01-25 
current Date is 2017-01-25 
fine is   $15 
15 
join Date is 2016-02-29 
due  Date is 2017-01-25 
current Date is 2017-02-24 
fine is   $15 
15 
join Date is 2016-02-29 
due  Date is 2017-01-25 
current Date is 2017-02-25 
fine is   $30 
30 

を要約すると、このようなライブラリを使用すると、intの数で考える必要がなくなり、日付とカレンダーの観点から実装する必要があるロジックに集中することができます。結果は、はるかに正しい可能性があるコンパクトで読みやすいコードです。 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"; 
} 

あなたには、いくつかの他の形式、here is the complete list of parsing flags available for useを求めることを好む場合。

そして、OPは現在の日付を取得する方法を尋ねます。複数の答えがあります。あなたはUTCでの現在の日付と内容であれば、それが最も簡単です:

using namespace std::chrono; 
using namespace date; 
year_month_day today = floor<days>(system_clock::now()); 

あなたのローカルタイムゾーンの現在の日付をしたい場合は、あなたが"date/tz.h"requires some installation)を使用する必要があり、この構文:

year_month_day today{floor<days>(make_zoned(current_zone(), 
              system_clock::now()).get_local_time())}; 

あなたが行うことができますあなたの現在のローカルタイムゾーン以外のいくつかの時間帯に現在の日付を希望しない場合:どんなにあなたのp

year_month_day today{floor<days>(make_zoned("America/Los_Angeles", 
              system_clock::now()).get_local_time())}; 

一般的なアドバイスが読みやすいようにコードをフォーマットしようとして

std::cout << membershipFine(join, today) << '\n'; 
+0

私はその人が参加した日付を入力するようにしたいので、どのタイプの変数を保存するのですか?月を数値から単語形式に変換するのにintとif文を使うことができますか?私はまた、現在の日付を取得するためにctimeを使用したので、あまりにも動作することができますか? – stylersolve

+0

'int'sを解析して' int'sを 'year_month_day'に変換することもできますし、' istream'の 'year_month_day'に直接構文解析する' parse'ユーティリティもあります。フォーマット。 'ctime'はフォーマッタなので、' time'を意味すると仮定し、 'time_t'から' std :: chrono :: system_clock :: time_point'に変換してから 'year_month_day'に変換する方法があります。私は 'system_clock :: now()'を使って現在の時刻を取得します。それはあなたにUTCを与えます。現地時間が必要な場合は、タイムゾーンライブラリもあります:https://howardhinnant.github.io/date/tz.html –

関連する問題