Vergangene Zeit berechen mit DS3231

Hallo,

ich möchte gerne zu einem bestimmten Datum die vergangene Zeit berechnen, meine Frage ist, wie ich das am geschicktesten mache damit die vergangene Zeit auch korrekt berechnet wird inkl. Schaltjahre.

Ich nutze den DS3231 und Arduino UNO. Welche Libraries sollte ich nutzen neben der Library für den DS3231?

Mir ist aufgefallen, dass der DS3231 den aktuellen Unix Timestamp zurückgeben kann als long. Das Problem ist, ich kann dieses long nicht zu einem float casten, da sonst der Timestamp nicht mehr stimmt. Allerdings muss ich den Rest berechnen. Das müsste ich dann aufwendig über eine Funktion mit while-Schleife realisieren.

Oder gibt es bereits eine Library welche die vergangene Zeit in Jahre, Monate, Wochen, Tagen, Stunden und Sekunden darstellen kann?

oino:
Oder gibt es bereits eine Library welche die vergangene Zeit in Jahre, Monate, Wochen, Tagen, Stunden und Sekunden darstellen kann?

Ja, solche Libraries gibt es. heißen meist “Time.h” und arbeiten intern mit “Unixzeit”.
Eine vollständige Time.h Implementierung enthält neben Funktionen zum Umgang mit Unixzeit und Julianischen Tageszahlen und Gregorianischem Kalender auch noch Funktionen zur Berechnung von Sonnenaufgangs- und Sonnenuntergangszeiten. Eine Time.h Library gehört bei Arduino nicht mit zum Lieferumfang der IDE. Jedenfalls nicht für die 8-Bit Atmega Plattform, bei den 32-Bit ARM plattformen weiß ich nicht.

Wenn Dir Kalender- und Zeitfunktionen fehlen, kannst Du entweder Drittanbieter-Libraries installieren oder Dir die benötigten Funktionen selbst programmieren. Da jeder Tag 86400 Sekunden hat, ist das gar nicht schwwierig.

Ach so: Heute hat natürlich 86401 Sekunden, weil um Mitternacht eine Schaltsekunde stattfindet.

Heute gibt es nach 23:59:59 Uhr noch die Schaltsekunde mit der Uhrzeit 23:59:60 Uhr. Aber für Unixzeit ist das egal. In Uniszeit wird die Schaltsekunde an Silvester 23:59:60 Uhr am 31.12.2016 so behandelt als wäre es die erste Sekunde im neuen Jahr, also identisch zu 00:00:00 Uhr am 01.01.2017.

Als “Unixzeit” kannst Du die Zahl der vergangenen Sekunden seit 01.01.1970 um 00:00 Uhr UTC-Zeit in einer “long” Variablen speichern. Jedenfalls bis irgendwann Anfang 2038, wenn der ‘long’ Sekundenzähler überläuft. Danach müßtest Du “unsigned long” oder int64_t nehmen.

Da man jede Datums-/Zeitangabe leicht in Unixzeit umrechnen kann, entweder mit einer Libraryfunktion oder mit einer selbstgeschriebenen Funktion. kannst Du die Differenz zwischen zwei Zeitangaben einfach durch Differenzbildung der Unixzeiten ermitteln. Das wäre dann ebenfalls in Sekunden und Du müßtest es Dir in Tage, Stunden, Minuten, Sekunden selbst umrechnen. Mit einer eigenen Funktion wie Du es brauchst.

Danke für deine Nachricht. Mein Problem ist herauszufinden wie viel Schaltjahre zwischenzwei Unixtimestamps sind und die Tage der einzelnen Monate. Konnte bisher keine Library finden welche das kann.

oino:
Danke für deine Nachricht. Mein Problem ist herauszufinden wie viel Schaltjahre zwischenzwei Unixtimestamps sind und die Tage der einzelnen Monate. Konnte bisher keine Library finden welche das kann.

Das kannst Du Dir doch ganz einfach ausrechnen!
Also das Jahr 1970, als die Unixzeit startete, war kein Schaltjahr.
Um die Anzahl der Schaltjahre zwischen zwei Unixzeiten herauszufinden, brauchst Du also nur wissen, wieviele 4-Jahresperioden die eine Unixzeit umfaßt und vieviele 4-Jahresperioden die zweite Unixzeit.

Die Anzahl der Sekunden in einer Vierjahresperiode ist immer konstant, da eine Vierjahresperiode immer 3 normale Jahre zu 365 Tagen und ein Schaltjahr mit 366 Tagen enthält.

const long secondsInfourYears=(3*365+366)*86400L;

Und nun reduziert sich das Problem darauf, herauszufinden, wie groß die Differenz an vergangenen Vierjahresperioden in beiden Zeitstempeln ist:

int anzahlVergangenerSchaljahre=unixTime2/econdsInfourYears - unixTime1/econdsInfourYears;

Dabei wäre nur darauf zu achten, dass unixTime2 der spätere und unixTime1 der frühere Zeitstempel ist.

Das müßte es meiner Meinung nach sein.

Die Anzahl der Tage zwischen zwei Unixtimestamps wäre entsprechend, gerechnet mit 86400 Sekunden pro Tag:

int anzahlVergangenerTage=unixTime2/86400- unixTime1/86400;

P.S.: Beim nochmaligen Nachdenken fällt mir auf, dass ich bei den Schaltjahren wohl doch etwas zu simpel gedacht habe. Tatsächlich würde man wohl noch eine for-Schleife und eine isLeapYear() Funktion verwenden müssen, damit die Ergebnisse für anzahlVergangenerSchaljahre IMMER korrekt werden.

Leider stimmt die berechnete Zeit nicht. Kann allerdings keinen Fehler in meiner Berechnung finden. Die Timestamps habe ich auch schon überprüft. Der Fehler liegt in den Stunden, eigentlich müsste er die aktuelle Stundenanzahl in 24h anzeigen, es wird aber 23 Stunden angezeigt.

#include <Time.h>
#include <TimeLib.h>

    #include <DS3231.h>

    DS3231  rtc(SDA, SCL);
  
    Time t;

void setup() {

  Serial.begin(115200);
  rtc.begin();
  

}

void loop() {

  
  t.hour = 0;
  t.min = 0;
  t.sec = 0;
  t.year = 2008;
  t.mon = 8;
  t.date = 6;
  
  
  long startDate = rtc.getUnixTime(t);
  long unixTimestamp = rtc.getUnixTime(rtc.getTime());
  long delta = unixTimestamp - startDate;
 
 Serial.print("Startdate: ");
 Serial.println(startDate);
 Serial.print("Current: ");
 Serial.print(unixTimestamp);
 Serial.print(" -- ");
 Serial.println(rtc.getTimeStr());
 
  long years =  delta / 31557600;

  delta = delta - (years * 31557600);
  
  
  long months = delta / 2629800;
  delta = delta - (months * 2629800);

  long weeks = delta / 604800;
  delta = delta - (weeks * 604800);
  
  long days = delta / 86400;
  delta = delta - (days * 86400);

  long hours = delta / 3600;
  delta = delta - (hours * 3600);

  long minutes = delta / 60;
  delta = delta - (minutes * 60);
  
  long seconds = delta;
  
  Serial.print(years); 
  Serial.print(" Jahre, ");
  Serial.print(months);
  Serial.print(" Monate, ");
  Serial.print(weeks);
  Serial.print(" Wochen, ");
  Serial.print(days);
  Serial.print(" Tage,");
  Serial.print(hours);
  Serial.print(" Stunden,");
  Serial.print(minutes);
  Serial.print(" Minuten, ");
  Serial.print(seconds);
  Serial.print(" Sekunden");
  Serial.println(" -- ");
  Serial.println(" -- ");
  
  delay(10000);

}

hi,

schaltjahre berechnen ist nicht ganz so trivial:

alle 4 jahre, außer die jahreszahl ist durch 100 teilbar, aber nicht durch 400.

da wir einen solchen sonder-sonderfall im jahr 2000 hatten, muß man das berücksichtigen.

gruß stefan

EDIT: übrigens wird die schaltsekunde nicht um mitternacht eingefügt, sondern um 2 uhr früh.

Das mit dem Schaltjahr ist mit dem Code den ich als letztes gepostet habe eingebaut. Allerdings wird die Stunde in meiner Berechnung falsch ausgegeben. Es wird aktuell Stunde 0 ausgegeben, eigentlich sollte es Stunde 18 ausgeben.

oino:
Leider stimmt die berechnete Zeit nicht. Kann allerdings keinen Fehler in meiner Berechnung finden.

Deine Berechnung ist falsch.

long years = delta / 31557600;

Das ist einfach, aber falsch gerechnet.

Es gibt kein einziges Jahr, das365.25 Tage mit 31557600 Sekunden enthält.
Es gibt keine Jahre mit einer nicht-ganzzahligen Anzahl von Tagen.
So bekommst Du nichtmal die Anzahl der Jahre ´in jedem Fall richtig heraus.
Jahre haben entweder 365 oder in Schaltjahren 366 Tage.

Aber auch wenn der Durchschnittswert365.25 Tage pro Jahr ist, so gibt es doch KEIN EINZIGES Jahr mit einer so krummen Tagesanzahl. Das kann nur schiefgehen.

Für die von Dir gewünschte Berechnung von Zeitdifferenzen in Jahren, Monaten, Tagen, Stunden, Minuten,Sekunden gibt es meines Wissens nach keine fertigen Library-Funktionen, sondern das mußt Du "zu Fuß" ausrechnen, anhand der konkreten Zeitstempel in der Form (Jahr,Monat,Tag,Stunde,Minute,Sekunde) und NICHT direkt aus der Unixzeit.
Aus der Differenz der Unixzeit bekommst Du zwar diese Werte leicht heraus:

  • vergangene Zeit in Sekunden
    -vergangene Zeit in Minuten
  • vergangene Zeit in Stunden
  • vergangene Zeit in Tagen
    Aber für eine Ausgabeformatierung in Jahren, Monaten, Tagen, Stunden,Minuten,Sekunden muss gerechnet werden.

jurs:
Aus der Differenz der Unixzeit bekommst Du zwar diese Werte leicht heraus:

  • vergangene Zeit in Sekunden
    -vergangene Zeit in Minuten
  • vergangene Zeit in Stunden
  • vergangene Zeit in Tagen
    Aber für eine Ausgabeformatierung in Jahren, Monaten, Tagen, Stunden,Minuten,Sekunden muss gerechnet werden.

Genau das mach ich doch, ich berechne die Werte die ich ausgeben möchte. Ich kriege über den Weg mit der Differenz per Unixtimestamp genauso viel Tage raus wie als wenn ich die vergangenen Tage selbst zählen würde. Die passen auch alle, bis auf den Wert der Stunden, und genau da liegt das Problem, ich weiss nicht woher das Problem mit den Stunden kommt.

oino:
Genau das mach ich doch, ich berechne die Werte die ich ausgeben möchte. Ich kriege über den Weg mit der Differenz per Unixtimestamp genauso viel Tage raus wie als wenn ich die vergangenen Tage selbst zählen würde. Die passen auch alle, bis auf den Wert der Stunden, und genau da liegt das Problem, ich weiss nicht woher das Problem mit den Stunden kommt.

Du machst doch überall Fehler in Deiner Rechnung. Wenn Du ein Jahr mit 365.25 Tagen rechnest, dann beträgt der Fehler in Nicht-Schaltjahren 0.25 Tage = 6 Stunden und in Schaltjahren 0,75 Tage= 18 Stunden. Und wenn Du einen Monat mit 30,4375 Tagen rechnest, dann beträgt der Fehler in Monaten mit 28 oder 29 Tagen (Februar) sogar mehr als 24Stunden, um die Du Dich verrechnest.

Du kannst nicht erwarten, dass sich alle systematischen Fehler am Ende der Rechnung zu null ausgleichen.

Eisebaer:
alle 4 jahre, außer die jahreszahl ist durch 100 teilbar, aber nicht durch 400.

da wir einen solchen sonder-sonderfall im jahr 2000 hatten, muß man das berücksichtigen.

Das Jahr 2000 war ein ganz normales Schaltjahr, da durch 400 teilbar. Die Regel muss berücksichtigt werden, wenn man das Jahr 1900 oder 2100 einbezieht.