Differenz zwischen 2 Datumswerten - ABER - Ergebnis gesucht in: Jahren, Monaten, Tagen, Stunden, Minuten und Sekunden

  • Liebe Profis,

    das Thema klingt zunächst banal, vielleicht ist es das für Euch auch, aber ich (Status Anfänger) stecke zumindest gerade fest.


    1) Ich möchte die Differenz zwischen 2 Datumswerten (incl. Zeit) berechnen (hier: Datum 1 = 2018/10/26 19:03:43 Datum 2 = 2009/06/30 14:05:16 )

    2) Beide Daten liegen im "Calc-Format" vor und mir ist die Funktion "_DateDiff" grundsätzlich bekannt

    3) Ich brauche jedoch eine Antwort im Stil: 9 Jahre, 3 Monate, 26 Tage, 4 Stunden, 58 Minuten, 27 Sekunden

    4) Mit meinen limitierten Fähigkeiten bin ich leider nur in Lage, die Differenz in einer Einheit zu berechnen (z.B.: 294.209.907 Sekunden oder 81.724 Stunden)

    5) Egal wie versuche diese Zahlen umzurechnen, es wird immer ungenau, weil ich nicht weiß, wie Schaltjahre etc. einzurechnen sind

    6) Kurzum: Ich schaffe es nicht, mittels Formel auf das korrekte Ergebnis wie in Zeile 3 zu kommen


    Ist das wirklich so schwierig oder sehe ich gerade den Wald vor lauter Bäumen nicht .... ?

    Vielen Dank schonmal im Vorraus für Euren Mühen / Ideen.


    Gruß Michael

  • Das ist eigentlich ziemlich einfach, du brauchst dazu nur die Funktion Int().

    Du schaust wie viele Jahre in der Zeit enthalten sind und trennst diese davon ab, mit Int() rundest du die Zahlen ab.

    Hast du 1.2 Jahre, so willst du am Ende 1 Jahr, xxx Monate, ... ausgeben und nicht 2 Jahre oder 1.2 Jahre.


    Du fängst von der größten Zeiteinheit an und rechnest dann immer runter, hier mal in Pseudocode


    zeit = 294209907 sekunden


    jahre = Int(zeit / (1jahr * 12monate * 30tage * 24stunden *60minuten *60sekunden))

    zeit = zeit - jahre * (1jahr * 12monate * 30tage *24stunden *60minuten *60sekunden)


    monate = Int(zeit / (1monat * 30tage *24stunden *60minuten *60sekunden))

    zeit = zeit - monate * (1monat * 30tage *24stunden *60minuten *60sekunden))


    tage = Int(zeit / (1tag *24stunden *60minuten *60sekunden)

    zeit = zeit - tage * (1tag *24stunden *60minuten *60sekunden)


    stunden = Int(zeit / (1stunde *60minuten *60sekunden)

    zeit = zeit - tage * (1stunde *60minuten *60sekunden)


    minuten = Int(zeit / (1minute * 60sekunden)

    zeit = zeit - tage * (1minute * 60sekunden)


    sekunden = zeit <-- vorausgesetzt du hast Sekunden und nicht Millisekunden

  • weil ich nicht weiß, wie Schaltjahre etc. einzurechnen sind

    Das ist - glaube ich - das größte Problem. Du hast bei der Angabe X Jahre, Y Monate, Z Tage zwangsläufig mit einem Informationsverlust zu kämpfen. Selbst nach alpines' Methode (die an sich eigentlich die richtige Lösung darstellt) unterscheidest du nicht zwischen normalen Jahren und Schaltjahren, geschweige denn nach Monaten mit unterschiedlich vielen Tagen (es wird pauschal 30 Tage angenommen).


    Deshalb wird das nicht die gewünschte Genauigkeit erbringen. Wenn ich dich richtig verstehe, möchtest du ja, dass bspw...

    - zwischen dem 1.1.2015 und dem 2.1.2016 genau 1 Jahr, 0 Monate und 1 Tag liegen.

    - zwischen dem 1.1.2016 und dem 2.1.2017 genau 1 Jahr, 0 Monate und 1 Tag liegen. (2016 ist ein Schaltjahr, d.h. das eine Jahr sind 366 Tage)


    Richtig?

  • Erstmal herzlichen Dank für die Anrworten! (Nur leider lösen sie mein Problem nicht.)


    alpines :

    Ab Berechnung der Tage geht's daneben. Die Diiferenz zwischen Datum 1 und 2 sind mit Deiner Berechnung 9 Jahre und 3 Monate, also 111 Monate (was auch korrekt ist).
    Multipliziert man die Monatsanzahl mit dem "Pauschalwert" 30 für die Tage, erhält man 3330 Tage. Zieht man diese Zahl von 3405 (dem korrekten Differenzwert in Tagen) ab, erhält man 75

    als "Restwert" (nach Abzug der vollen Monate über die "Int"-Funktion). Es dürften aber nur 26 sein?!


    Das Problem liegt also bei den Tagen, da diese nicht mit einem "Pauschalwert" berechnet werden dürfen wenn man ein genaues Ergebnis benötigt. Ich habe es auch mit dem Annährungswert
    365,25 Tage pro Jahr versucht, dies wird aber insbesondere bei kurzen Zeitspannen ungenau - was ja auch klar ist ...


    Nach vielen Grübelstunden heute Nacht ist mir eine Lösung eingefallen, die ich jetzt aber noch irgendwie in eine "Formel gießen" muss, vielleicht kann mir dabei jemand helfen?
    1. Das Enddatum muss immer das größere sein. Somit: 2009/06/30 14:05:16 = Startdatum, 2018/10/26 19:03:43 = Enddatum

    2. Man berechnet beim Startdatum die Zeitdifferenz bis Mitternacht des Tages. Also von 14:05:16 bis "24:00:00" => somit 09:54:44 (fortan als Zeit 1 benannt)

    3. Dann berechnet man die vollen Tage bis zum letzten Tag des Monats (vom Startdatum) => hier 0, weil der Juni 30 Tage hat. (Dieses Ergebnis nenne ich Tage 1)

    4. Beim Enddatum geht man genau umgekehrt vor. Man berechet die Differenz von Mitternacht des Tages bis zur "Enduhrzeit", hier also 19:03:43 (Bezeichnung als Zeit 2)

    5. Dann berechnet man die Tage bis zum ersten Tag des Monats (vom Enddatum) => hier 25 (nicht 26!!!) Bezeichnung = Tage 2

    6. Man addiert Zeit 1 und 2 = 28:58:27 => 1 Tag und 04:58:27

    7. Man addiert die Werte Tage 1 und Tage 2 (plus ggf. die vollen Tage aus 6) => 0 + 25 + 1 = 26 Tage

    8. (Hier nicht der Fall) - aber sollte die Zahl aus 7) größer sein als die Anzahl der Tage im Monat des Startdatums (Juni = 30 Tage) , muss man diese vom Ergebnis aus 7) abziehen, dafür Monate + 1

    9. Die Monate kann man einfach aus der "_DafeDiff" Funktion übernehmen und in Jahre & "Rest" umrechnen => 111 Monate, also 9 Jahre und 3 Monate (ggf. + Monat aus 8 )
    So kommt man zum korrekten Ergebnis 9 Jahre, 8 Monate, 26 Tage, 4 Stunden, 58 Minuten und 27 Sekunden


    Recht komplex, aber nach meiner Einschätzung dennoch zu machen, insbesondere weil man Schaltjahre usw. nicht beachten muss.

    Vielleicht hat ja jemand eine Idee für eine Funktion, die die o.a. Schritte umsetzt?


    Allen ein schönes Wochenende!

  • Ich würde alles den Funktionen _DateDiff + _DateAdd überlassen. Hier der angefangene Ansatz:

    da dies eine C & P (mit Search + Replace) Lösung wird ist sie leicht zu vervollständigen und du must dir keine Gedanken um Schaltjahre machen. Bei dieser Methode wird jeweils die ganzzahlige Differenz (in Jahren/Monaten/Tagen usw.) ermittelt und danach in der jeweiligen Einheit zum ältereren Datum addiert.


    Basierend auf diesem Ansatz hier eine kürzere Lösung:

  • Danke autoBert,

    aber das Problem sind tatsächlich die Tage. Monate und Jahre lassen sich ja problemlos über _"DateDiff" bestimmen.

    Die "_DateDiff" - Funktion gibt auch die Tagesanzahl korrekt wieder (3405) - aber mir ist keine Formel bekannt, um sie korrekt in Jahre und Monate umzurechnen.

  • Das kannst du auch nicht. Das ist der von mir angesprochene Informationsverlust. Du kannst aus Tagen nicht wieder Monate oder Jahre machen.


    Du musst bei der Differenzbildung schrittweise bei der größten Einheit (Jahre) anfangen. Wenn das nicht mehr geht, mit Monaten weitermachen usw...


    So kann man das schön simpel machen:

    Edit:


    Kurz nochmal der Algorithmus in Worte gefasst. Mag effizienter gehen, aber so habe ich es auf einem Blatt Papier auch gelöst.

    1. Beginne bei Einheit Jahren.

    2. Addiere so lange 1 Einheit auf das Startdatum, bis es bei der nächsten Addition größer als das Enddatum wäre. Zähle dabei die Additionen.

    3. Ausgehend von dem neuen Startdatum wiederhole Schritt 2 mit der nächstkleineren Einheit, bis keine nächstkleinere Einheit mehr existiert.

    4. Die gezählten Additionen sind der Abstand der beiden Daten.

  • Hallo kilo !

    alpines :

    Ab Berechnung der Tage geht's daneben.

    alpines wollte im Rahmen seines Pseudocodes ja auch nur einen Denkanstoss geben. Dass nicht alle Monate 30 Tage lang sind ist ihm sicher klar :P

    Ich habe es auch mit dem Annährungswert 365,25 Tage pro Jahr versucht

    Die Länge von 365,25 Tagen (nicht 365) ist der eigentliche Grund für die Einführung von Schaltjahren !

    Das astronomische Jahr ist aber etwas kürzer als 365,25 Tage (365,2425), daher wird gelegentlich ein Schaltjahr ausgelassen.

    Regel :

    Alle ganzzahlig durch vier teilbaren Jahre (modulo 4 = 0) sind Schaltjahre, mit Ausnahme der Jahrhunderte, die nicht durch 400 teilbar sind.

    Die UDF date.au3 liefert dafür die Funktion _DateIsLeapYear. Einfach mal 'reinschauen :)

    (Nebenbei : 'moderne' Schaltjahre gibt es erst seit 1600 n.Chr.)


    Nach vielen Grübelstunden heute Nacht ist mir eine Lösung eingefallen, die ich jetzt aber noch irgendwie in eine "Formel gießen" muss,

    So in der Art könnte es ggf. aussehen. Ich habe vor Jahren so etwas in einem rudimentären PASCAL-Dialekt gemacht. Mal sehen ob ich die Zeit finde, das zu übertragen ^^.


    Edit : Zwischenzeitlich sind ja Lösungsansätze von autoBert und chesstiger hinzugekommen.

    Möglicherweise ist das Problem damit ja bereits gelöst.


    Mal eine Frage an alle :

    In der Hilfe zu _DateDiff steht in den Bemerkungen :

    Gültige Datumsangaben müssen zwischen "2000/01/01 00:00:00". und "3000/12/31 23:59:59" liegen

    Ist das korrekt ?


    Gruß Musashi

    "Die Definition von Wahnsinn ist, immer wieder das Gleiche zu tun und andere Ergebnisse zu erwarten." - Albert Einstein

  • chesstiger !

    Nachtrag :

    Deine Variante scheint super zu funktionieren :thumbup:.


    Kleine Testserie :

    $sDateA = "2017/03/02 12:00:00"

    $sDateB = "2016/02/01 12:00:00"

    ; -> 1 Jahre, 1 Monate, 1 Tage, 0 Stunden, 0 Minuten, 0 Sekunden


    $sDateA = "2017/04/02 12:00:00"

    $sDateB = "2016/03/01 12:00:00"

    ; -> 1 Jahre, 1 Monate, 1 Tage, 0 Stunden, 0 Minuten, 0 Sekunden


    $sDateA = "2017/03/02 12:00:00"

    $sDateB = "1997/02/01 12:00:00"

    ; -> 20 Jahre, 1 Monate, 1 Tage, 0 Stunden, 0 Minuten, 0 Sekunden


    EDIT :

    Gleiches gilt für den Beitrag #10 von autoBert  


    Gruß Musashi

    "Die Definition von Wahnsinn ist, immer wieder das Gleiche zu tun und andere Ergebnisse zu erwarten." - Albert Einstein

    Einmal editiert, zuletzt von Musashi ()

  • aber das Problem sind tatsächlich die Tage. Monate und Jahre lassen sich ja problemlos über _"DateDiff" bestimmen.

    Die "_DateDiff" - Funktion gibt auch die Tagesanzahl korrekt wieder (3405) - aber mir ist keine Formel bekannt, um sie korrekt in Jahre und Monate umzurechnen.

    mein Ansatz war und ist von der größten Einheit (Jahre) bis zur kleinsten Einheit (Sekunden) jeweils die Differenz zu ermitteln und diese mit _DateAdd zum Startdatum zu addieren. Da ich die endgültige Lösung erst danach hinei editiert habe und mitlerweile noch einmal für die Ausgabe angepasst habe, noch einnmal das Skript:

    obige Skript liefert mit deinen Orginaldaten: 9/3/26 4:58:27

    wenn ich die Uhr-Zeiten vertausche: 9/3/25 19:1:33. Die Ergebnisse sind Jahre/Monate/Tage Stunden:Minuten:Sekunden formatiert.

    Man kann also daran erkennen, daß die Macher der Date.au3 alles was nötig ist bereits berücksichtigt haben. Und falls du nicht die letzten Millisekunden bei der Berechnung herausquetschen musst/willst ist diese Art zu lösen die Bequemste.

  • Das Problem reduziert sich doch eigentlich auf die Berücksichtigung möglicher Schaltjahre. Ich würde so vorgehen (Start < Ende) :

    - Differenz Tage bis Jahresende

    - Anzahl Jahre bis Jahr Ende

    - Anzahl Tage im Endjahr

    Evtl. Schaltjahre berücksichtigt _DateDiff.

    Das einzige NICHT lösbare Problem entsteht, wenn die Summe der Tage (Rest Start + Tage in Ende) 365 überschreitet. Das ergibt kein reales Jahr + Resttage, sondern ein fiktives Jahr. Und das kannst du eigentlich nur mit der Länge eines Normaljahres veranschlagen.

    Wegen solcher Unwägbarkeiten hat sich zum Bsp. die Finanzwelt das 360 Tage Jahr (12 Monate a 30 Tage) geschaffen.

  • Ganz herzlichen Dank Euch allen !!! Es ist wie so häufig im Leben: Viele Wege führen nach Rom bzw. zum Ziel.


    Das es aber mit so kurzen Programmcodes geht, nötigt mir immer wieder Respekt ab! Ihr seid schon echt gut.
    Die Chancen, dass ich mich irgendwann mal revanchieren kann, stehen bedauerlicherweise eher schlecht ...

    da werden wohl noch etliche Jahre vergehen, bis ich dahin komme ...


    Vielen Dank nochmal!