ich habe ein Programm geschrieben, welches einen NTP-Zeitserver abfragt und aus dem empfangenen Datenpaket Datum und Uhrzeit berechnet und diese auf dem seriellen Monitor ausgibt.
Das funktioniert soweit auch alles ganz gut, allerdings ist der Tag des Datums falsch. Es ist immer ein Tag zu wenig. Wenn z.B. das Datum der 14.12.2018 ist, dann gibt das Programm "13.12.2018" aus.
Die Berechnung erfolgt direkt aus der NTP-Zeit (Sekunden seit 01.01.1900) und diese Zeit wird auch korrekt vom Zeitserver empfangen (ich habe mir den Zeitstempel anzeigen lassen, daraus die UNIX-Zeit bestimmt und mir anschließend daraus online das Datum und die Uhrzeit berechnen lassen -> Zeitstempel ist korrekt).
Der Code, der das Datum berechnet ist folgender:
...
// Variablen
uint32_t timeInSeconds ;
uint8_t month, dayMonth;
uint16_t year;
// NTP-Zeitserver abfragen
// Gibt die Anzahl der Sekunden zurück, die seit dem 01.01.1900 vergangen sind
timeInSeconds = RequestNTP();
// Eine Stunde aufaddieren, da Deutschland = UTC+1h ist
timeInSeconds += 3600;
// Jahr berechnen
// Sekunden durchschnittliches Jahr (365,25 Tage): 31557600UL
// Anzahl von 4-Jahresblöcken berechnen, die seit 1900 vergangen sind
uint8_t blocks = (timeInSeconds / (4 * 31557600UL));
// Vorläufige Jahreszahl berechnen
year = START_YEAR_NTC + (4 * blocks);
// Anzahl der verbleibenden Sekunden berechnen
// (Sekunden seit 1900 - Sekunden aller 4-Jahresblöcke)
uint32_t remainingSeconds = (timeInSeconds - (4 * blocks * 31557600UL));
// Bis zu 3 Jahre auf die vorläufige Jahreszahl addieren
// Nach der obigen Berechnung können max. 3 Jahre dazu kommen, da anonsten "leastSeconds" 0 wäre
for (uint8_t i=0;i<3;i++)
{
// Kein Schaltjahr (Sekunden normales Jahr: 31536000UL)
if (year % 4)
{
if (remainingSeconds >= 31536000UL)
{
year++;
remainingSeconds -= 31536000UL;
}
}
// Schaltjahr (Sekunden Schaltjahr: 31622400UL)
else
{
if (remainingSeconds >= 31622400UL)
{
year++;
remainingSeconds -= 31622400UL;
}
}
}
// Monat berechnen
month = 1;
// Februar mit 28 Tagen = 2419200UL s
// Februar mit 29 Tagen = 2505600UL s
// 30-Tage Monat = 2592000UL s
// 31-Tage Monat = 2678400UL s
while (remainingSeconds >= 2419200UL)
{
// Monate mit 31 Tagen
// (außer Dezember, da ansonsten Jahreswechsel stattfinden würde)
if ((month == 1)
|| (month == 3)
|| (month == 5)
|| (month == 7)
|| (month == 8)
|| (month == 10))
{
if (remainingSeconds >= 2678400UL)
{
month++;
remainingSeconds -= 2678400UL;
}
}
// Monate mit 30 Tagen
else if ((month == 4)
|| (month == 6)
|| (month == 9)
|| (month == 11))
{
if (remainingSeconds >= 2592000UL)
{
month++;
remainingSeconds -= 2592000UL;
}
}
// Februar im Nicht-Schaltjahr
else if ((month == 2)
&& (year % 4))
{
if (remainingSeconds >= 2419200UL)
{
month++;
remainingSeconds -= 2419200UL;
}
}
// Februar im Schaltjahr
else if ((month == 2)
&& !(year % 4))
{
if (remainingSeconds >= 2505600UL)
{
month++;
remainingSeconds -= 2505600UL;
}
}
}
// Monatstag berechnen
dayMonth = 1;
dayMonth += (remainingSeconds / 86400UL);
...
Kann mir jemand sagen, wo der Fehler in der Berechnung liegt?
Vielen Dank
Du brauchst auch nicht zu schreiben, dass Du die Antwort als nutzlos empfindest. Du bekommst keine andere von mir.
Gruß Tommy
User wie "gregorss" haben in solchen Foren nichts zu suchen. Sein Beitrag hat nichts zur Lösung des geschilderten Problems beigetragen ist damit nutzlos.
Arrogante Fragesteller, wie Du, noch viel weniger.
Er hat Dich lediglich auf eine mögliche Fehlerquelle hingewiesen, weil Du für UTC- und localtime die gleiche Variable verwendet hast. Du hast es nur nicht begriffen.
AArduinoO:
User wie "gregorss" haben in solchen Foren nichts zu suchen. Sein Beitrag hat nichts zur Lösung des geschilderten Problems beigetragen ist damit nutzlos.
Ich sehe das anders. Ich sehe daß solche Fragesteller in solchen Foren nichts zu suchen haben.
Das schlimme an meiner Meinung ist ich bin einer der Moderatoren.
Tommy56:
Arrogante Fragesteller, wie Du, noch viel weniger.
Ich drücke mich klar aus und antworte auf Fragestellungen exakt, problembezogen und zielführend.
So wie sich das für ein deutschsprachiges Forum gehören sollte.
Für manche mag das arrogant wirken.
Tommy56:
[...]
Er hat Dich lediglich auf eine mögliche Fehlerquelle hingewiesen, weil Du für UTC- und localtime die gleiche Variable verwendet hast. Du hast es nur nicht begriffen.
Und Tschüß
Tommy
Das wäre lediglich dann eine Fehlerquelle, wenn wir uns zeitlich um 23:x Uhr (0 <= x <= 59) befinden würden. Dies ist aber nicht der Fall, da ich im ersten Post geschrieben habe:
" Es ist immer ein Tag zu wenig. " (man beachte das Wort "immer")
Hätte "gregorss" meinen Beitrag vernünftig gelesen und über das Problem nachgedacht, so hätte er bemerkt, dass er sich seinen Post hätte sparen können.
@Serenifly: Du hast Recht. Lesefehler von mit, wobei ich keine Deklaration von uctTime in seinen Beiträgen finde, der Code also wohl nichtmal kompiliert.
Tommy56: @Serenifly: Du hast Recht. Lesefehler von mit, wobei ich keine Deklaration von uctTime in seinen Beiträgen finde, der Code also wohl nichtmal kompiliert.
Gruß Tommy
Sie wird nicht bei der Definition deklariert, jedoch ein paar Zeilen weiter:
timeInSeconds = RequestNTP();
Die Funktion gibt eine 32-Bit Variable zurück, welche den Zeitstempel der NTP-Anfrage enthält (Byte 40 bis 43).
da gibts ne ganze menge Vorschläge wie man Dein grudsätzliches Anliegen lösen kann.
PS: Ich sehe ja ein das Du uns testen wolltest, eigendlich hast Du keine sinvolle Antwort mehr verdient, und ich denke das sehen andere ebenso, dennoch etwas damit das mit einem Lösungsansatz geschlossen werden kann.
AArduinoO:
Das funktioniert soweit auch alles ganz gut, allerdings ist der Tag des Datums falsch. Es ist immer ein Tag zu wenig.
Obwohl die Stimmung hier am Boden ist, werde ich mal helfen ^^
Die Aussage aus dem Quoting ist meiner Meinung nach falsch. Die Berechnung stimmt zumindest, ohne dass ich den Taschenrechner in Hand genommen habe oder den Code ausgeführt habe, für den gesamten Januar 1990. Man könnte jetzt hergehen und den Anfangswert der Variablen mal händisch auf bestimmte Werte setzen und prüfen ab wann der Algorithmus nicht mehr funktioniert.
Deshalb ein Tipp zu Selbsthilfe: Verrechnet sich der Algorithmus tatsächlich immer genau um einen Tag oder siehst du nur diesen Rechenfehler weil du dir Stunde, Minute, Sekunde nicht ausrechnest und ausgibst? Da würde man nämlich evtl. erkennen, dass der Algorithmus mit fortschreitendem timeInSeconds-Wert immer weiter abdriftet (Erstmal nur meine Vermutung).
Ich lehn mich mal aus dem Fenster und behaupte, dass der Fehler in dem Sekunden-Wert für ein mittleres Jahr liegt. Das mittlere Jahr hat nämlich nicht 365,25 Tage sondern nur ca. 365,2425 Tage. Nach gut 119 Jahren hast du also mittlerweile einen Rechenfehler von ca. 1 Tag drin.