2017-10-30 4 views
-2

Ich versuchte, ein Programm zu machen, das die Gebühr einer Mitgliedschaft in einem Schwimmbad berechnete. Der Benutzer würde ein Datum eingeben (das letzte Mal, an dem ein Mitglied die Mitgliedschaft erneuert), und das Programm würde berechnen, ob seine Mitgliedschaft überfällig war oder nicht, unter Verwendung des aktuellen Datums.Mit Monat und Datum zusammen in C++

Die Mitgliedschaft ist für eine Woche (oder eine andere willkürliche Zeitspanne) vor dem Beginn des Monats, in dem sie in einem Jahr beigetreten sind, überfällig. Zum Beispiel, wenn ich im Februar 2016 beigetreten bin, müsste ich am 24. Januar 2017 oder vorher zahlen, um sicherzustellen, dass die Mitgliedschaft überfällig ist. Sobald es 25. Januar wird, sollte eine monatliche Gebühr erhoben werden ($ 15) und sobald es 25 Februar erreicht, sollte zwei Monate Gebühr usw. berechnet werden.

Allerdings weiß ich nicht, wie man für nachfolgende Gebühr Monate nach dem ersten. Zum Beispiel sollte die Zahlung am 3. Februar zu einem Monat führen, aber die Zahlung am 26. Februar sollte zwei Monate dauern, aber ich weiß nicht, wie ich das machen soll.

Wie kann ich meine Funktion reparieren, weil es nicht zu funktionieren scheint? Zum Beispiel Ich trat 15 2016 November und es sollte 15 zurückkehren, da die Mitgliedschaft am 24. Oktober 2017 fällig war, aber es gibt 0 zurück

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

Ein genereller Rat versuchen, den Code zu formatieren, um einfach zu lesen. Zeigen Sie auch, was der tatsächliche Fehler oder die unerwartete Ausgabe ist. Es scheint ein Teil der Hausaufgabe zu sein, die Frage herauszufinden, die du fragst. – MrJLP

Antwort

1

Der beste Weg, mit Daten und Zeiten zu beschäftigen ist eine Bibliothek zu verwenden, die das Niveau Steigerungen in Höhe von Abstraktion über Ganzzahlen, zu Daten und Zeiten. Howard Hinnant's free, open-source, header-only library ist ein solches Werkzeug.

Es hat eine {year, month, day} Klasse namens date::year_month_day, die sich für Jahres- und Monatsarithmetik eignet. Man könnte diese verwenden, um die API von membershipFine von unter 6 typ unsicheren Parameter nur zwei typsichere Parameter zu ändern:

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

Ihre Beschreibung des Fälligkeitsdatums zu sagen scheint, dass es des Tages der unabhängigen Monat des Beitrittsdatums und dass es ein Jahr ist, weniger als eine Woche ab dem ersten des Monats des Beitrittsdatums. Wenn dies wahr ist, kann dies leicht wie folgt berechnet werden:

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

Der Ausdruck joinDate.year()/joinDate.month() schafft ein year_month Objekt, das nur ein Jahr und Monat, unter Vernachlässigung des Tag-of-the-Month von joinDate. Ich füge 1 Jahr zu diesem year_month hinzu, das in anderem year_month resultiert, genau 1 Jahr später.

Zu dieser Summe ist /1 angehängt. Dies erzeugt einen year_month_day, der dem ersten Tag des Monats der zuvor erwähnten year_month entspricht.

Nun, obwohl year_month_day für year und month orientierte Arithmetik groß ist, ist es nicht so groß, für Tag und Woche orientierte Arithmetik. Die beste Datenstruktur dafür ist eine {count-of-days} aus einer Epoche. Diese Bibliothek hat eine solche Datenstruktur, die local_days genannt wird. Also wandle ich dazu um, subtrahiere 1 Woche und konvertiere dann wieder zurück in .

All dies (um das Fälligkeitsdatum zu berechnen) passiert in den Zeilen des obigen Codes.

Jetzt muss ich die fine basierend auf der Beziehung zwischen currentDate und dueDate berechnen.Die fine ist $ 0, wenn currentDate < dueDate, und sonst ist eine Funktion der Anzahl der ganzen Monate (plus 1) currentDate ist jenseits dueDate (wie ich verstehe Ihre Problemstellung):

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

Der Unterschied in Monaten, den Tag zu vernachlässigen -of-the-month, kann durch Umwandlung in year_month Objekte berechnet und subtrahiert werden. Jetzt, wenn currentDate.day() < dueDate.day(), ist dies die richtige Antwort. Wenn zum Beispiel der Unterschied in Monaten 1 ist, aber der Tag des Monats in currentDate den Tag des Monats in dueDate noch nicht überschritten hat, dann wollen wir nicht für einen zweiten Monat berechnen, sonst tun wir es. Wenn wir das tun, wird differenceInMonths inkrementiert.

Dann ist die fine einfach die differenceInMonths, von months zu Integral umgewandelt, mal 15.

<aside> Wenn es irgendwelche <chrono> Fans da draußen, die Art der differenceInMonths ist eigentlich ein std::chrono::duration mit einer Periode, die genau die Durchschnittsmonat. So die .count() Mitglied Funktion zum Zugriff auf den zugrunde liegenden Integralwert.

Ich habe einige print-Anweisungen zu den obigen Code hinzugefügt und unten zeigen, dass ich das Ganze zusammen und einen Treiber mit einigen Beispielen:

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

Diese Ausgänge:

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 

Zusammenfassend lässt sich durch die Verwendung einer solchen Bibliothek nicht mehr von int s denken, damit Sie sich auf die Logik konzentrieren können, die Sie in Bezug auf Daten und Kalender implementieren müssen. Das Ergebnis ist ein kompakter und lesbarer Code, der weitaus wahrscheinlicher ist.

aktualisieren

In den Kommentaren unter dem OP fragt, wie ein Datum aus cin zu analysieren und wie das aktuelle Datum zu erhalten. Es gibt mehrere Möglichkeiten.

Hier ist, wie ich empfehlen, für ein Datum zu fragen:

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

Wenn Sie lieber für ein anderes Format fragen, here is the complete list of parsing flags available for use.

Und das OP fragt, wie man das aktuelle Datum bekommt. Es gibt mehrere Antworten.Wenn Sie mit dem aktuellen Datum in UTC Inhalt sind, das ist die einfachste:

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

Wenn Sie das aktuelle Datum in Ihrer Zeitzone wollen, müssen Sie "date/tz.h" (requires some installation) und diese Syntax verwenden:

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

Wenn Sie das aktuelle Datum in irgendeiner anderen Zeitzone als die aktuelle Zeitzone wollen, kann diese mit erfolgen:

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

Egal, wie Sie p ass Ihre join und today, können sie wie folgt verwendet werden:

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

Ich möchte, dass der Benutzer das Datum eingibt, an dem sich die Person angeschlossen hat, also welchen Typ von Variable würde ich darin speichern? Könnte ich einfach int und eine if-Anweisung verwenden, um den Monat von numerisch in Wortform umzuwandeln? Ich habe auch ctime verwendet, um das aktuelle Datum zu bekommen, kann das auch funktionieren? – stylersolve

+0

Sie könnten 'int's und dann von' int' in 'year_month_day' konvertieren, oder es gibt auch ein 'parse'-Dienstprogramm, das Sie verwenden können, um direkt in' Jahr_Monat_Tag' von 'iStream' in einer Vielzahl von zu analysieren Formate. 'ctime' ist ein Formatierer, also nehme ich an, du meintest' time', und es gibt eine Möglichkeit, von 'time_t' zu' std :: chrono :: system_clock :: time_point' und dann zu 'year_month_day' zu konvertieren, aber Ich würde einfach 'system_clock :: now()' verwenden, um die aktuelle Zeit zu erhalten. Das gibt Ihnen UTC. Wenn Sie Ortszeit benötigen, gibt es auch eine Zeitzonenbibliothek: https://howardhinnant.github.io/date/tz.html –

Verwandte Themen