Hi ihr Cracks,
Ich versuche derzeit die Unixzeit richtig aufzuschlüsseln, liege
teilweise aber immer etwas daneben. Vielleicht hat einer von euch mal
die Zeit und Muße kurz über meinen Code zu gucken um meinen Fehler zu
identifizieren.
Beispiele:
Winterzeit:
Wenn ich den Wert 973070045 umwandel, würde ich gerne die Lokalzeit
01.11.2000 10:14:05 herausbekommen. Mein Ergebnis ist aber der
02.11.2000 9:14:05. Also um einen Tag und eine Stunde falsch.
Sommerzeit:
Wenn ich den Wert 1339745796 umwandel, würde ich gerne die Lokalzeit
15.06.2012 09:36:36 herausbekommen. Mein Ergebnis ist aber der
16.06.2012 08:36:36. Also um einen Tag und zwei Stunden falsch.
Ich kann aber irgendwie keinen Fehler finden, vielleicht fällt euch das
leichter.
Der Code besteht aus den folgenden 2 Funktionen:
Du könntest einfach in der C-Bibliothek nachschauen, wie es da gemacht
wird. Eine entsprechende Funktion wäre 'localtime()', die Quellen dazu
sind frei.
Und bitte, BITTE gewöhne dir den Schwachsinn mit diesem '_s32' wieder
ab. Bitte!
Und nein, dieses '_s32' hat absolut garnichts mit der ungarischen
Notation zu tun, wirklich nicht. Das ist schlicht die Perversion einer
eigentlich ganz guten Idee, nachdem Microsoft ebendiese völlig falsch
verstanden hat...
Es ist mir ehrlich gesagt etwas zu nervig, mir zu überlegen, was du mit
so etwas meinst:
leap400_s32 = (s32)(4 - (((FIRSTYEAR - 1) / 100) & 3));
Wenn man schon arithmetische Rechnung und Bitfummelei vermmatscht,
könnte man wenigstens sagen, was man damit meint.
Daß man in solchem Code Fehler suchen muß, ist nicht selten.
Spaß macht es nicht, weil es mit klarer Programmierung vermeidbar wäre.
PS: Wenn es dir zu anstrengend ist, (int32_t) zu schreiben und ein
eigenes (s32) baust, wieso castest du unnötigerweise dann jeden Kram?
Hallo,
Die Notationen entsprechen den mir vorliegenden Richtlinikatalog und
sind keinesfalls meinen eigenem Gutdünken entsprungen. Also bitte
tollerieren.
Das explizite Casten liegt einfach daran das ich C-Code nach Lint bzw.
MISRA Richtlinien programmiere. Dort ist implizites casten untersagt.
Dennoch Danke für eure Rückantworten :-)
Das mit localtime schaue ich mir einmal an.
Übrigens noch ein Nachtrag: Bei der von dir zitierten Zeile handelt es
sich um eine BErechnung für die 400Jahres-Sonderregel für Schaltjahre.
Und ja du hast recht - hier fehlt ein Kommentar.
Tachoron schrieb:> Hallo,>> Die Notationen entsprechen den mir vorliegenden Richtlinikatalog und> sind keinesfalls meinen eigenem Gutdünken entsprungen. Also bitte> tollerieren.
Naja, armer Kerl :-)
> Das explizite Casten liegt einfach daran das ich C-Code nach Lint bzw.> MISRA Richtlinien programmiere. Dort ist implizites casten untersagt.
Dann solltest du das aber auch richtig umsetzen.
Die ganzen expliziten Casts nach der Form:
1
(s32)100
sind nämlich überflüssig bis falsch, wenigstens in vor-C90-Compilern.
Einfachs Beispiel für eine Maschine, bei der 'int' genau 32 Bit lang
ist:
1
unsignedintu1=2147483648;
2
unsignedintu2=(unsignedint)2147483648;
3
if(u1==(unsignedint)2147483648);
Compilerausgabe:
1
test.c:287: Warnung: diese Dezimalkonstante ist nur in ISO-C90 vorzeichenlos
2
test.c:288: Warnung: diese Dezimalkonstante ist nur in ISO-C90 vorzeichenlos
3
test.c:290: Warnung: diese Dezimalkonstante ist nur in ISO-C90 vorzeichenlos
Was du vermutlich erreichen wolltest:
1
unsignedintu=2147483648U;
Oder, wenn man eben nicht sämtliche Typen blödsinnigerweise
nachdefiniert:
1
#include<stdint.h>
2
uint32_tu=UINT32_C(2147483648);
Naja, vermutlich wieder typische Fehlinterpretation :-)
Tu dir selbst einen Gefallen und lass so einen Quatsch bleiben
1
if((year_s32&(s32)3)==(s32)0)
wenn du Modulo meinst, dann schreib auch Modulo. Diese 'wahnsinnig
clevere' Optimierung beherrschen Compiler seit ungefähr 40 Jahren völlig
problemlos (und noch viele mehr, die du nicht kennst). Dafür solltest du
lieber nachdenken, warum deine Datentypen eigentlich alle signed sind?
Denn gerade bei signed Datentypen stimmt diese 'Optimierung' nämlich
NICHT. Bei negativen Zahlen geht das in die Hose. Und wenn du jetzt
einwendest, du hättest keine negativen Zahlen, dann frag ich dich: warum
sind deine Datentypen dann nicht in erster Linie 'unsigned'?
Du addierst bzw subtrahierst hier immer wieder
eine 1.
Gewöhn dich daran, dass wir Programmierer bei 0 anfangen zu zählen.
Eine kanonische for-Schleife, die zb alle Arrayelemente durchgeht
lautet
for( i = 0; i < Anzahl_Elemente; i++ )
mach was mit Array[i];
* bei 0 wird zu zählen angefangen
* da steht immer ein 'kleiner' in der Bedingung.
Sieht eine for-Schleife so aus, braucht man nicht groß weiter darüber
nachdenken. Sieht sie aber nicht so aus, dann werd ich SOFORT hellhörig
und muss das analysieren. Und öfter als man glaubt, hat der
Programmierer dann da tatsächlich einen Fehler eingebaut, den er mit der
kanonischen Form vermieden hätte. Wenn, so wie bei dir, das eigentlich
gar keine Zählschleife ist, solltest du darüber nachdenken, ob du nicht
zu dokumentarischen Zwecken lieber eine ordinäre while einsetzen
solltest. Das betont mehr, dass da die Abbruchbedingung eine spezielle
Bedeutung hat.
Hmm
1
(*day_ps32)=day_s32+(s32)1;/*1...31*/
du addierst da noch 1 und dein tagesdatum ist um 1 zu groß.
Zusammenhang?
Noch was. Ich akzeptiere, dass du jeden Pfurz casten musst (auch wenn
ich persönlich das für Unsinn im MISRA halte). Aber mach dir um Gottes
Willen wenigstens für die Konstanten ein paar #define. In deinem Code
kann man doch vor lauter Castings nichts mehr erkennen! Das ist doch
unsinnig, jeden Pfurz ständig zu casten (zumal es ja auch den Compiler
nicht daran hindert, das Ergebnis hinten nach noch einmal implizit zu
casten. Woran es ihn aber ganz sicher hindert ist: Ordentlich zu
optimieren.)
> Ich kann aber irgendwie keinen Fehler finden, vielleicht fällt> euch das leichter.
Gehs halt mal systematisch an.
Jag die Unixzeit 0 durch und steppe im Debugger durch.
Dann für 1 Stunde mehr, 1 Tag mehr, für 1 Jahr mehr, für 1 Schaltjahr
mehr.
Da jetzt irgendeine Zeit (=große Zahl) einzusetzen, für die du das
Ergebnis kennst, ist meistens nicht sehr zielführend um rauszukriegen,
welche der Berechnungen in die Hose geht.
Oder (wenn das mit dem Debugger zu langweilig ist) ab 1.1.1970
fortlaufend mit der Funktion aus der C-Lib vergleichen lassen und beim
ersten Unterschied mit dem Debugger reingehen.
Tachoron schrieb:> Bei der von dir zitierten Zeile handelt es> sich um eine BErechnung für die 400Jahres-Sonderregel für Schaltjahre.
Bis ins wievielte Jahrtausend muss denn deine Software funktionieren?
Die 100- und 400-Jahres-Regeln hoben sich im Jahr 2000 auf. Alle
Software, die bis zum Jahr 2099 in der Datenmülltonne landet (weil
man deren Datenträger bis dahin sowieso nur noch mit Mitteln der
Archäologie exhumieren kann ;) muss sich darum folglich keine weiteren
Gedanken machen und kann das Schaltjahr einfach mittels modulus 4
ermitteln.
Tachoron schrieb:> Wenn ich den Wert 1339745796 umwandel, würde ich gerne die Lokalzeit> 15.06.2012 09:36:36 herausbekommen. Mein Ergebnis ist aber der> 16.06.2012 08:36:36. Also um einen Tag und zwei Stunden falsch.
Der Unterschied beträgt nur 1 Tag und 1 Stunde.
Folgende Fehler habe ich in deinem Code gefunden:
1. Die 1 Stunde Differenz kommt von daher, dass die Unix-Zeit am
1.1.1970 um 00:00:00 UTC zu zählen beginnt. Zu diesem Zeitpunkt war
es aber nach MEZ schon 01:00:00. Um die Ergebnisse in MEZ zu
erhalten, musst du also 1 Stunde zum berechneten Ergebnis addieren.
2. Der eine Tag kommt von der folgende Schleife:
1
do
2
{
3
dayofyear_s32=365;
4
/*Schaltjahr?*/
5
.
6
.
7
.
8
if(day_s32>=dayofyear_s32)
9
{
10
day_s32-=dayofyear_s32;
11
year_s32++;
12
}
13
}while(day_s32>=dayofyear_s32);
hinterlässt dayofyear_s32 mit der Anzahl der Tage des Jahres vor dem
Abfragedatum. Du benutzt die Variable aber anschließend, um zu
entscheiden, ob das Jahr des Abfragedatums selbst ein Schaltjahr ist.
Deswegen ist das Ergebnis in Schaltjahren ab dem 1. März immer 1 Tag
zu groß.
3. Der 1.1.1970 war kein Samstag (6), sondern ein Donnerstag (4).
Dadurch sind die berechneten Wochentage falsch, was wiederum
Auswirkungen auf die Sommerzeitberechnung hat.
4. Falls die Routine auch für die Vergangenheit funktionieren soll: Die
Sommerzeitumstellung hat sich seit 1970 ein paarmal geändert:
http://de.wikipedia.org/wiki/Sommerzeit#Deutschland
Möglicherweise enthält der Code noch weitere Fehler. Ich würde ihn
deswegen für alle Tage von 1970 bis 2201 jeweils mindestens für die
Uhrzeiten 01:00 und 03:00 (wegen der Sommerzeitumstellung um 02:00)
durchlaufen lassen und die Ergebnisse mit denen eines validierten
Programms (z.B. date von Unix/Linux oder eine entsprechende Biblio-
theksfunktion) vergleichen.
Hallo Yalu,
Ich komme leider erst sehr spät zum Antworten aber danke für deine sehr
konstruktive und hilfreiche Antwort!
Das mit dem Tag hatte ich bis dato auch herausgefunden, die anderen
Punkte aber so noch nicht.
Hat mir in jedem Fall sehr geholfen!
Gruß
Dennis