Datum: 03.01.2005 11:41
Oft werden Datum und Uhrzeit als 32 Bit Zahl der vergangenen Sekunden seit einem Stichtag dargestellt, z.B. in Filesystemen oder in RTC-Bausteinen wie dem DS1994. Damit kann aber keiner was anfangen, d.h. man muß diesen 32 Bit-Wert erst in Datum und Uhrzeit umrechnen. Anbei ein einfacher Beispielkode, der auf 8-Bit CPUs optimiert ist. Es werden also möglichst viele Variablen als 8-Bit definiert und möglichst wenig Divisionen bzw. keine Divisionen in Schleifen verwendet. Als erstes erfolgt die Berechnung der Zeit durch fortgesetzte Division mit Rest. Leider erwiesen sich da sowohl der Keil C51 als auch der AVR-GCC wenig optimierungsfreudig. Obwohl die Divisionsroutine gleichzeitig den Quotienten und den Rest ermittellt, rufen beide die Divisionsroutine zweimal auf. Der etwas schwerere Teil ist die Datumsermittlung. Da 2^32 Sekunden nur 136 Jahre umfassen, muß zuerst ein Startwert festgelegt werden, z.B. der 1.1.2000. Um nun die Jahreszahl zu ermitteln, wird in einer Schleife für jedes Jahr ermittelt, ob es ein Schaltjahr ist und dementsprechend werden 365 oder 366 Tage abgezogen. Da es nur max 136 Jahre sind und keine Division in der Schleife erforderlich ist, ist der Rechezeitaufwand minimal. Die 100- und 400-Jahres Regel wird berücksichtigt. Danach wird dann die Tagesanzahl je Monat abgezogen und die Monate hochgezählt. Übrig bleiben die Tage. Sommerzeit: Die Sommerzeit beginnt am letzten Sonntag um 2.00Uhr im März und endet zum gleichen Zeitpunkt im Oktober. Zuerst werden die Monate 1, 2, 11, 12 ausgeschlossen und dann wird auf den Umschaltzeitpunkt getestet. Vor dem Umschaltzeitpunkt wird im März abgebrochen und nach dem Umschaltzeitpunkt im Oktber. Dann wird die Stunde um 1 erhöht und eine eventuelle Weiterschaltung von Tag, Wochentag und Monat behandelt. Anbei das komplette Beispielprogramm für den Keil C51 Peter
Datum: 03.01.2005 19:48
Respekt Peter ! Das wollte ich schon immer mal sagen. Eine 100 oder 400 Jahresregel hätte ich sicher nicht berücksichtigt :) Ich bin zwar überzeugter Assembler Programmierer und kann deshalb die C-Sachen nicht übernehmen aber ich finde es echt super, dass du etliche Sourcen zur Verfügung stellst. Grüße, Alex
Datum: 02.02.2005 05:37
Auch von mir Beifall für diesen Code!
Datum: 15.07.2005 15:21
Hallo!
Hat jemand zufälig eine routine, mit der es möglich ist, einen
"besetzten" time-Typen:
struct time {
u8 second;
u8 minute;
u8 hour;
u8 day;
u8 month;
u16 year;
u8 wday;
};
in Sekunden seit einem Stichtag zurückzurechnen?
Beispiel:
unsigned long sec2000; // u32, Sekunden seit 1.1.2000
time->year = 2005;
time->month=7;
time->day=15;
_getsecond_(sec2000, &time);
--> Im Moment sieht die Anwendung vor, dass man Minute, Stunde per
Display einstellen kann. Dazu addiere/subtrahiere ich nach
ensprechendem Tastendruck auf die Var. sec2000 einfach 3600 für
Stunden, 60 bei Minuten usw.
Aber wie mache ich es, wenn ich den Tag/Monat/Jahr in/dekrementieren
will?
Über einen Beitrag bin ich sehr dankbar
mfG
Datum: 15.07.2005 15:33
Hallo Robert, ich habe Dein Problem noch nicht so ganz verstanden. Warum bleibst Du nicht einfach bei struct time? Aber wenn Du die struct time in einen long wandeln willst, kannst Du mktime() benutzen. Bsp. ........... struct time *tm; time_t timelong; tm->year = 105; tm->mon = 7; tm->mday = 15; timelong = mktime(tm); ........... Joline
Datum: 15.08.2005 13:20
hier hast was. musst es eventuell noch etwas umbauen für deine
bedürfnisse. wohl hauptsächlich das:
/* Start with 1900 a.d. */
result -= 693961L;
wenn du mit 1.1.1980 bzw. 1970 arbeiten willst
struct rdcf_date_and_time
{
unsigned char second;
unsigned char minute;
unsigned char hour;
unsigned char day;
unsigned char month;
unsigned short year;
};
/*
Calculates seconds from date since 01.01.1900, 00:00:00
*/
unsigned long SecondsFromTime (struct rdcf_date_and_time *t)
{
unsigned char i;
unsigned long result = 0;
unsigned int idx;
/* days of each month */
unsigned char md[] = {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30,
31};
/* Make month an array index */
idx = t->month - 1;
/* Leap year? adjust february */
if (t->year%400 == 0 || (t->year%4 == 0 && t->year%100 !=0))
md[1] = 29;
else
md[1] = 28;
/* Calculate days of years before */
result = (unsigned long)t->year * 365;
if (t->year >= 1)
{
result += (t->year+3) / 4;
result -= (t->year-1) / 100;
result += (t->year-1) / 400;
}
/* Start with 1900 a.d. */
result -= 693961L;
/* Loop thru each month, adding the days */
for (i=0; i<idx; i++)
result += md[i];
/* Add remaining days */
result += t->day;
/* Convert to seconds, add all the other stuff */
result = (result-1) * 86400L + (unsigned long)t->hour * 3600 +
(unsigned long)t->minute * 60 + t->second;
return result;
}
Datum: 02.11.2005 10:48
Hallo Peter, ich habe mir mal die Fkt. summertime mal angeschaut, weil ich in einer meiner Anwendungen auch eine solche Unterscheidung einbauen muss. Dafür wollte ich deine Fkt. anpassen. Nun versteh ich leider einen Punkt in der zweiten If-Abfrage nicht:
if( day - wday >= 25 && (wday || hour >= 2) if( month == 10 ) return; |
Warum (wday || hour >=2)? Hour >=2 versteh ich ja, aber wday || hour? Ist Sonntag == 0?
Datum: 02.11.2005 10:58
"Ist Sonntag == 0?" Ja, ich habs von der PC-Funktion "get date" so übernommen. Steht auch ganz oben bei der Definition der Startzeit. Peter
Datum: 24.04.2006 16:08
Hallo Peter, toller Code! Ich steh aber momentan auf dem Schlauch. Denn ich möchte aus dem Struct, also dem Datum/Uhrzeit den Wert in Sekunden ermitteln. Deine Funktion also, nur anders herum. Hast Du da einen Tip parat? Viele Grüße Stefan
Datum: 25.04.2006 14:22
@Stefan, ein Ausschnitt aus den "zeitmanipulationen" die ich seit vielen Jahren verwende und teilweise auf AVRs portiert habe (verwendet zB PROGMEM). Nachdem das "ausgeschnitten" ist kann ich aber nicht garantieren dass es in dieser Form fehlerfrei Compiliert. Viel Erfolg Werner
Datum: 25.04.2006 15:19
Ahh jetzt sehe ich was ich rausgeschnitten hatte... In MakeTime_t am Ende noch "second + (60 * (minute + 60 * hour))" addieren. Aber der Kommentarteil "... bis ... 0:00:00" trifft es
Antwort schreiben
Die Angabe einer Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
- Groß- und Kleinschreibung verwenden
- Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
- JPEG-Dateien (.jpg) nur für Fotos und Scans verwenden
- Schaltpläne, Screenshots usw. als PNG oder GIF anhängen
Formatierung (mehr Informationen...)
- [c]C-Code[/c]
- [avrasm]AVR-Assembler-Code[/avrasm]
- [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
- [math]Formel in LaTeX-Syntax[/math]
- [[Titel]] - Link zu Artikel


