Forum: Projekte & Code Berechnung Datum + Uhrzeit + Sommerzeit


von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

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

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Und hier das komplette Beispielprogramm für den AVR-GCC :-)

Peter

von Alexander Niessen (Gast)


Lesenswert?

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

von Herrmann Jahnke (Gast)


Lesenswert?

Auch von mir Beifall für diesen Code!

von Robert Wachs (Gast)


Lesenswert?

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

von Joline (Gast)


Lesenswert?

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

von LalaDumm (Gast)


Lesenswert?

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;
}

von Slowflyer (Gast)


Lesenswert?

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:
1
if( day - wday >= 25 && (wday || hour >= 2) 
2
    if( month == 10 )        
3
      return;

Warum (wday || hour >=2)?
Hour >=2 versteh ich ja, aber wday || hour?
Ist Sonntag == 0?

von Peter Dannegger (Gast)


Lesenswert?

"Ist Sonntag == 0?"

Ja, ich habs von der PC-Funktion "get date" so übernommen.

Steht auch ganz oben bei der Definition der Startzeit.


Peter

von Stefan (Gast)


Lesenswert?

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

von Werner B. (Gast)


Angehängte Dateien:

Lesenswert?

@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

von Werner B. (Gast)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.