Datums berechnungen


  • Gesperrt

    @DocShoe sagte in Datums berechnungen:

    Das nennst du funktionsfähig? Tut mir leid, wenn ich dir da an den Karren fahren muss, aber ne. Die Einschränkungen sind so groß, dass das praktisch nicht zu gebrauchen ist.

    Wie gesagt, beide Zeitpunkte müssen nur innerhalb desselben Jahres liegen und es darf sich nicht um ein Schaltjahr handeln. Andernfalls ist das Ergebnis undefiniert.



  • @DocShoe sagte in Datums berechnungen:

    Die date-Bibliothek von Hinnant findest du gut und intuitiv?

    Intuitiv: naja. Man muss sich schon daran gewöhnen. Overengineert: definitiv! Für 99% der Fälle möchte ich eine einfache Klasse ohne Templates, aber mit vielen nützlichen Memberfunktionen haben.

    Mich nervt, dass ich mit .day() usw. immer herumcasten muss, um wieder einen int herauszubekommen. Deswegen habe ich einen eigenen Wrapper um die date.h, die die Typsicherheit etwas zurücknimmt und die Klassen damit für mich benutzbarer macht. Auch würde ich gerne eine Duration auf ein Datum addieren können. Deswegen hat mein Wrapper auch eine Funktion addDays(int n). So, wie es jetzt ist, muss man umwandeln. Ist sicher gemacht, damit man explizit sieht, wo Umwandlung stattfindet und wo man besser effizient addieren könnte. Aber es nervt schon ein wenig.

    Ich finde den ganzen Krempel mit den vielen Clocks überflüssig. Wird sicher jemand brauchen - ich nicht. Und klar, die verschiedenen Zeit-Granularitäten mit den ratios gibt es auch noch. Wobei das schon sinnvoll ist, denn manch einer wird sicher ns-Präzision brauchen und man anderer wird mit Tagesgenauigkeit zufrieden sein.

    Diese date::*-Klassen sind doch schon ein Schritt, std::chrono benutzbar zu machen.


  • Mod

    Das scheinbare Overengineering liegt in der Natur der Sache. Denn das Thema selbst ist kompliziert, viel komplizierter als man zunächst denkt. Einerseits weil das System an sich schon semi-kompliziert ist. Andererseits weil Datumsangaben eine solch durchdringend wichtige Rolle im menschlichem Zusammenleben ausmachen, dass die Komplexität menschlicher Interaktion in das Thema überschwappt.

    Wenn man da naiv dran geht, kommt so etwas wie bei EinNutzer0 heraus. Wenn man etwas weniger naiv dran geht, kommt so etwas heraus, wie die native Kalenderunterstützung in vielen Programmiersprachen. Also Datumsangaben, und Deltas (in Tagen, Stunden, etc.) dazwischen, die für sich genommen auch korrekt funktionieren. Das ist dann die korrekte Umsetzung der technischen semi-komplizierten Aspekte, ohne die menschlichen Interaktionen.

    Aber da hört es ja in der Praxis nicht auf, denn dort braucht man oft solche Dinge wie "plus ein Monat" (klingt einfach, aber was heißt das genau?), "erster Montag des Monats", "wie vielte Woche des Jahres" (an welchem Tag fängt die Woche an? Unterstützen wir lieber mehrere…), "wie viele Monate zwischen diesen beiden Datumsangaben?", zig verschiedene Eingabeformate, Feiertage (Ortsabhängig! Veränderlich!), Zeitzonen. Und von nicht-gregorianischen Kalendersystemen will ich gar nicht erst anfangen. Und dann kommt man halt bei den vermeintlich overengineerten Zusatzbibliotheken für Datumsverarbeitung an, die es dann auch für jede praxisrelevante Programmiersprache gibt.

    PS: Man sieht schön, wie leicht man das Thema unterschätzt, denn ich habe diesen Beitrag bestimmt 5x editiert, weil mir immer weitere Verkomplizierungen eingefallen sind. Allen davon bin ich im Berfufsleben schon begegnet.


  • Gesperrt

    @SeppJ Richtig interessant wird es doch erst bei der Miteinbeziehung von Schaltjahren, Schaltsekunden und Sommer- und Winterzeit im gregorianischen Kalender. 😉 Beispielweise gibt es in einem Vertrag eine stunden- oder minutengenaue Abrechnung. Hans Müller hat einen Monatsvertrag am 5.6.2017 um 15:59 Uhr geschlossen, am 7.8.2019 um 23:20 Uhr kündigt er zum nächstmöglichen Zeitpunkt und 60,5 Stunden später gelangt diese in den Kenntnisbereich des Vertragspartners - der nicht genutzte Zeitraum soll ihm erstattet werden. Los, fang an zu rechnen. 😉



  • @EinNutzer0 sagte in Datums berechnungen:

    kündigt er zum nächstmöglichen Zeitpunkt und 60,5 Stunden später gelangt diese in den Kenntnisbereich des Vertragspartners - der nicht genutzte Zeitraum soll ihm erstattet werden. Los, fang an zu rechnen.

    Dazu müsste ich erst einmal deinen Gedankengang verstehen. Und: was ist ein "Monatsvertrag"? Wie funktioniert dieser bei kürzeren Monaten? Deswegen ist Monat auch keine vordefinierte duration.

    Rechne einfach alles in UTC. Du brauchst die Umwandlung von Lokalzeit nach UTC bei der Eingabe und zurück bei der Ausgabe.

    Ansonsten kann chrono auch problemlos mit Studen und Minuten etc. umgehen. Und für Zeitzonen guckst du hier: https://howardhinnant.github.io/date/tz.html


  • Gesperrt

    Mein Beispiel war nicht vollständig. Ich wollte damit nur verdeutlichen, dass es sehr schnell sehr kompliziert werden könnte, wenn man wirklich alles selber machen will, und es deshalb doch ratsam ist, auf bestehende Lösungen zurückzugreifen, wie ihr schon richtig gesagt habt.


  • Gesperrt

    Noch eine Idee, wie findet ihr sie?:

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


  • @EinNutzer0 sagte in Datums berechnungen:

    wie findet ihr sie?

    Beschissen.

    @EinNutzer0 sagte in Datums berechnungen:

    und es deshalb doch ratsam ist, auf bestehende Lösungen zurückzugreifen


  • Gesperrt

    @Swordfish sagte in Datums berechnungen:

    Beschissen.

    Deine Antworten sind heute sehr differenziert. 😉



  • Deine Vorschläge haben weiterhin die bekannten Probleme. Was ist MyDate(28, 2).addDays(1)? Wie soll man das sinnvoll benutzen?



  • @EinNutzer0 Du sagst selbst man soll gefälligst getestete und etablierte Bibliotheken benutzen und kommst dann mit Schwachsinn??? Troll0r??? Wie in den anderen Threads an denen Du Dich beteiligst disqualifizierst Du Dich für eine sinnvolle Diskussion. Friss ein Lehrbuch zu C++ und Du solltest mindestens drei Monate beschäftigt sein. Dann hat es vielleicht sinn mit Dir zu reden. </rant>



  • @EinNutzer0 sagte in Datums berechnungen:

    Noch eine Idee, wie findet ihr sie?:

    class MyDate
    {
    public:
        tm *tp;
    

    Alleine schon die 3,5 Zeilen. 85 % der Leser sollten das instant-kotzen bekommen.

    https://en.cppreference.com/w/cpp/chrono

    @wob, @SeppJ und @manni66 haben dazu schon alles gesagt. Mach dich nützlich und setzte das um oder *Dieter-Nuhr-Zitat*.



  • @EinNutzer0 sagte in Datums berechnungen:

    Noch eine Idee, wie findet ihr sie?:

    tt += (days * 86400);
    

    Nicht jeder Tag hat 86.400 Sekunden, manchmal gibt es auch einen mit 86.401 Sekunden und das folgt leider keinem festen Muster. Ich denke addDays muss schon in Tagen rechnen, dann ist es egal ob es sich um einen Tag mit einer Schaltsekunde handelt oder nicht. Ich sag nur "Rabbit Hole".


  • Mod

    @Finnegan sagte in Datums berechnungen:

    Nicht jeder Tag hat 86.400 Sekunden, manchmal gibt es auch einen mit 86.401 Sekunden und das folgt leider keinem festen Muster. Ich denke addDays muss schon in Tagen rechnen, dann ist es egal ob es sich um einen Tag mit einer Schaltsekunde handelt oder nicht. Ich sag nur "Rabbit Hole".

    Das zumindest ist unwichtig, solange du kein Astronom oder Atomuhrbetreiber bist. Der Witz an Schaltsekunden ist, dass man so tut, als gäbe es sie nicht. Das heißt, für Zeitberechnungen ist 86.400 Sekunden immer korrekt, auch wenn eine mitlaufende Uhr etwas anderes gemessen haben würde.



  • @SeppJ sagte in Datums berechnungen:

    Das zumindest ist unwichtig, solange du kein Astronom oder Atomuhrbetreiber bist.

    Hah! Tatsächlich. Ich weiss schon warum ich sowas nicht selbst baue. Nicht nur gibt's da vieles, das man leicht vergisst zu berücksichtigen, sondern auch jede Menge, von dem man nur glaubt, es berücksichtigen zu müssen. In der Summe kann da nur Mist bei rumkommen 😉



  • @SeppJ Ja, und @EinNutzer0 ist dann der erste der ankommt und sich über Ungenauigkeiten in 10^3 Jahren beschwert.


  • Gesperrt

    @Swordfish sagte in Datums berechnungen:

    Du sagst selbst man soll gefälligst getestete und etablierte Bibliotheken benutzen

    Hab ich doch gemacht, oder ist ctime etwa keine getestete Bibliothek? Manchmal verstehe ich die Aufregung nicht.



  • @EinNutzer0

    Es geht hier um Einiges mehr, der öffentliche Zugriff auf tp ist schon Käse. Hast du dir mal überlegt, wo der der Zeiger eigentlich herkommt, auf was er zeigt, und was bei der Verwendung von mehreren MyDate Klassen passieren kann?



  • ... und bei dem was @DocShoe hier nochmal für Dich verständlich klar ausdrückt liest man halt einfach nicht weiter sondern wirfts weg.


  • 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.


Anmelden zum Antworten