Datums berechnungen


  • Gesperrt

    Hier bitte, fluent:

    #include <iostream>
    #include <string>
    #include <ctime>
    
    class MyDate
    {
    public:
        MyDate(int day, int month)
        {
            time_t tt = time(0);
            tm *tp = localtime(&tt);
            tp->tm_mday = day;
            tp->tm_mon = month - 1;
            tp->tm_sec = 0;
            tp->tm_min = 0;
            tp->tm_hour = 0;
            my_time = mktime(tp);
        }
        MyDate addDays(int days)
        {
            time_t tt = my_time;
            tt += (days * 86400);
            return MyDate(tt);
        }
        time_t *getTimePointer()
        {
            return &my_time;
        }
    
    private:
        time_t my_time;
        MyDate(time_t tt) : my_time{tt} {};
    };
    
    int main()
    {
        std::cout << ctime(MyDate(1, 11).addDays(-7).addDays(14).addDays(-14).getTimePointer()) << "!\n";
        std::cout << ctime(MyDate(1, 11).addDays(365).getTimePointer()) << "!\n";
    }
    

    Das IST eine funktionierende Lösung ohne zusätzliche Libs. Nur bei return &my_time; bin ich mir nicht sicher.

    Was ist MyDate(28, 2).addDays(1)? Wie soll man das sinnvoll benutzen?

    Das würde sich je nach aktuellem Schaljahr richtig verhalten, also im Schaltjahr 29.2. und nicht im Schaltjahr 1.3.



  • @EinNutzer0
    Warum gibts du bei getTimePointer() einen Pointer auf Klasseninternas zurück?

    Damit bindest du die Gültigkeit des Zeigers an die Lebensdauer der Klasse.



  • @EinNutzer0 sagte in Datums berechnungen:

    Das IST eine funktionierende Lösung ohne zusätzliche Libs.

    Die Lösung steht in Post #3 dieses Threads.


  • Gesperrt

    @Quiche-Lorraine sagte in Datums berechnungen:

    @EinNutzer0
    Warum gibts du bei getTimePointer() einen Pointer auf Klasseninternas zurück?

    Damit bindest du die Gültigkeit des Zeigers an die Lebensdauer der Klasse.

    Damit ich die Ausgabe in eine Zeile schreiben könnte. 😉

    Wie lange wäre bei std::cout << ctime(MyDate(1, 11).addDays(365).getTimePointer()) << "!\n"; eigentlich die Lebensdauer der Klasse MyDate?


  • Gesperrt

    @Swordfish https://github.com/HowardHinnant/date ist doch eine zusätzliche, externe Lib... KISS-Prinzip.



  • @EinNutzer0
    Die ist beim ctime Aufruf schon kaputt, weil du ein temporary zurückgibst. Und da das temporary weder an eine lokale Variable zugewiesen wird noch deren Lebensdauer durch Bindung an eine const-Referenz verlängert wird erzeugt der ctime Aufruf UB, weil das Temporary da schon wieder zerstört wurde.
    Also nix " IST eine funktionierende Lösung", da hilft auch Captain Capslock nicht.

    PS:
    Für eine vernünftige Ausgabe überlädt man std::ostream& operator<<( std::ostream& ) und exponiert keine Klasseninterna.



  • @EinNutzer0 sagte in Datums berechnungen:

    @Swordfish https://github.com/HowardHinnant/date ist doch eine zusätzliche, externe Lib... KISS-Prinzip.

    Der Cmake Code zum einbinden der lib umfasst 5 Zeilen mit ordentlicher Formattierung. Das erscheint mir etwas simpler als den Code selbst zu schreiben 😃

    Also warum nochmal sich selbst den Kopf zerbrechen, wenn es auch einfacher geht?


  • Gesperrt

    @DocShoe sagte in Datums berechnungen:

    Für eine vernünftige Ausgabe überlädt man std::ostream& operator<<( std::ostream& ) und exponiert keine Klasseninterna.

    Oder man hätte eine Funktion getCtime, die einen string zurückgibt, imho. Ja ich hatte mir schon gedacht, dass return &my_time; problematisch ist...



  • @Leon0402 sagte in Datums berechnungen:

    Der Cmake Code zum einbinden der lib umfasst 5 Zeilen mit ordentlicher Formattierung. Das erscheint mir etwas simpler als den Code selbst zu schreiben

    So viel? Die date.h ist ein Header, der von nichts abhängt. Da brauchst du gar nichts weiter zu machen. Einfach Header #includen und fertig.

    Ich finde die Lösung von @EinNutzer0 wegen der Jahresproblematik recht unbrauchbar. Sie verfehlt schon einmal das Ziel, sinnvoll allgemein brauchbar zu sein. Wofür soll ich das sinnvoll einsetzen außer für den einzigen Zweck, einem Datum des aktuellen Jahres Tage zu addieren? Der Einsatzzweck wird unnötig eingeschränkt -> schlechtes Design. Und Typsicherheit? Warum (day, month) und nicht (month, day)? Man muss es nachschauen und kann es falsch machen. So nervig das Casten in date.h/chrono manchmal ist, man kann sich jedenfalls immer sicher sein, dass das richtige passiert und man keine Parameter vertauscht hat.


  • Gesperrt

    Hier nochmal, hoffentlich ohne UB:

    #include <iostream>
    #include <string>
    #include <ctime>
    
    class MyDate
    {
    public:
        MyDate(int day, int month)
        {
            time_t tt = time(0);
            tm *tp = localtime(&tt);
            tp->tm_mday = day;
            tp->tm_mon = month - 1;
            tp->tm_sec = 0;
            tp->tm_min = 0;
            tp->tm_hour = 0;
            my_time = mktime(tp);
        }
        MyDate addDays(int days)
        {
            time_t tt = my_time;
            tt += (days * 86400);
            return MyDate(tt);
        }
        std::string toString()
        {
            return ctime(&my_time);
        }
    
    private:
        time_t my_time;
        MyDate(time_t tt) : my_time{tt} {};
    };
    
    int main()
    {
        std::cout << MyDate(1, 11).addDays(-7).addDays(14).addDays(-14).toString() << "!\n";
        // Sun Oct 25 01:00:00 2020
        std::cout << MyDate(29, 3).addDays(-2).toString() << "!\n";
        // Fri Mar 27 00:00:00 2020
    }
    

    Wofür soll ich das sinnvoll einsetzen außer für den einzigen Zweck, einem Datum des aktuellen Jahres Tage zu addieren?

    Weil eigentlich danach gefragt wurde. 😉 Aber im Produktivsystem würde ich das eigentlich auch nicht einsetzen wollen...



  • @EinNutzer0 sagte in Datums berechnungen:

    Weil eigentlich danach gefragt wurde.

    Ja?

    @lucki1000 sagte in Datums berechnungen:

    Gibt's da irgendwelche "Best practices" oder sogar eine Lib?


  • Gesperrt

    @manni66

    @lucki1000 sagte in Datums berechnungen:

    wie ich zb 7 Tage vom 1.11 abziehen kann



  • @EinNutzer0 sagte in Datums berechnungen:

    @manni66

    @lucki1000 sagte in Datums berechnungen:

    wie ich zb 7 Tage vom 1.11 abziehen kann

    Ja, du kannst sogar die Frage nicht finden.


  • Gesperrt

    @manni66 Nö, es ist ein ganz eindeutiges Beispiel gewählt worden. Ich interpretiere 1.11. als 1.11.2020 und nicht als 1.11.1900. 🤔



  • @DocShoe sagte in Datums berechnungen:

    @EinNutzer0
    Die ist beim ctime Aufruf schon kaputt, weil du ein temporary zurückgibst. Und da das temporary weder an eine lokale Variable zugewiesen wird noch deren Lebensdauer durch Bindung an eine const-Referenz verlängert wird erzeugt der ctime Aufruf UB, weil das Temporary da schon wieder zerstört wurde.

    Kannst du das bitte genauer erklären? Lebt das Temporary nicht auf jeden Fall so lange, bis der äußere Aufruf von ctime abgeschlossen ist?

    siehe https://en.cppreference.com/w/cpp/language/lifetime

    All temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created, and if multiple temporary objects were created, they are destroyed in the order opposite to the order of creation. This is true even if that evaluation ends in throwing an exception.



  • @wob sagte in Datums berechnungen:

    So viel? Die date.h ist ein Header, der von nichts abhängt. Da brauchst du gar nichts weiter zu machen. Einfach Header #includen und fertig.

    Ja, man kann natürlich auch die lib reinkopieren. Aber das finde ich nicht die beste Art, eine Lib einzubinden. Man sieht nicht, welche Version der lib man verwendet und muss jedes mal die header austauschen, wenn man die version updaten will.



  • @EinNutzer0 sagte in Datums berechnungen:

    Hier bitte, fluent:

    MyDate addDays(int days)
    {
     // ...
     return MyDate(tt);
    }
    

    Mit "fluent" hat das aber nichts zu tun, da du jedesmal ein neues Objekt erzeugst.
    So wäre es richtiger:

    MyDate& addDays(int days)
    {
      my_time += days * 86400;
      return *this;
    }
    

    PS: Und eine Konstante (e.g. SecondsPerDay) für das Literal wäre auch angebrachter.



  • @wob @DocShoe Nene, das passt schon.



  • @EinNutzer0 sagte in Datums berechnungen:

    Wie lange wäre bei

    std::cout << ctime(MyDate(1, 11).addDays(365).getTimePointer()) << "!\n";
    

    eigentlich die Lebensdauer der Klasse MyDate?

    Wie sieht das denn aus wenn Du den Funktionsaufruf ausschreibst statt dem Operator <<? Kannst Du Dir die Frage dann selbst beantworten?



  • @wob sagte in Datums berechnungen:

    @DocShoe sagte in Datums berechnungen:

    @EinNutzer0
    Die ist beim ctime Aufruf schon kaputt, weil du ein temporary zurückgibst. Und da das temporary weder an eine lokale Variable zugewiesen wird noch deren Lebensdauer durch Bindung an eine const-Referenz verlängert wird erzeugt der ctime Aufruf UB, weil das Temporary da schon wieder zerstört wurde.

    Kannst du das bitte genauer erklären? Lebt das Temporary nicht auf jeden Fall so lange, bis der äußere Aufruf von ctime abgeschlossen ist?

    siehe https://en.cppreference.com/w/cpp/language/lifetime

    All temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created, and if multiple temporary objects were created, they are destroyed in the order opposite to the order of creation. This is true even if that evaluation ends in throwing an exception.

    Huch, hast recht! Ich bin davon ausgegangen, dass das temporäre MyDate Objekt direkt nach dem GetTimePointer() Aufruf zerstört wird, weil es nicht mehr benötigt wird und nur der Zeiger weiterverwendet wird.

    ideone


Anmelden zum Antworten