www.mikrocontroller.net

Forum: Projekte & Code Berechnung Datum + Uhrzeit + Sommerzeit


Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Und hier das komplette Beispielprogramm für den AVR-GCC :-)

Peter

Autor: Alexander Niessen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Herrmann Jahnke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch von mir Beifall für diesen Code!

Autor: Robert Wachs (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Joline (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: LalaDumm (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: Slowflyer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
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?

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Werner B. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Werner B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail ü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

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.