Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 21 Zeitroutinen
  gp 21.1 Die Headerdatei <time.h>
    gp 21.1.1 Konstanten in der Headerdatei <time.h>
    gp 21.1.2 Datums – und Zeitfunktionen in <time.h>
  gp 21.2 Laufzeitmessung (Profiling)

Kapitel 21 Zeitroutinen

In der C-Standard-Bibliothek sind einige Funktionen enthalten, mit denen Sie die Zeit bestimmen können. Die Zeit umfasst dabei das Datum und die Uhrzeit.


Galileo Computing - Zum Seitenanfang

21.1 Die Headerdatei <time.h>  downtop

Es folgen einige Standardfunktionen der Headerdatei <time.h>, in denen Routinen für Zeit und Datum deklariert sind. Dazu ein kurzer Überblick über die speziellen (primitiven) Datentypen in dieser Headerdatei und ihre Bedeutungen:


Tabelle 21.1   (Primitive) Datentypen und Struktur für Datum und Zeit

Typ Bedeutung
size_t arithmetischer Datentyp für Größenangaben
clock_t arithmetischer Datentyp für CPU-Zeit
time_t arithmetischer Datentyp für Datum- und Zeitangabe
struct tm enthält alle zu einer Kalenderzeit (gregorianische) relevanten Komponenten

Laut ANSI C-Standard sollten in der Struktur tm folgende Komponenten enthalten sein:


Tabelle 21.2   Bedeutung der Strukturvariablen in struct tm

struct tm-Variable Bedeutung
int tm_sec; Sekunden (0–59)
int tm_min; Minuten (0–59)
int tm_hour; Stunden (0–23)
int tm_mday; Monatstag (1–31)
int tm_mon; Monate (0–11) (Januar = 0)
int tm_year; ab 1900
int tm_wday; Tag seit Sonntag (0–6) (Sonntag =0)
int tm_yday; Tag seit 1. Januar (0–365) (1.Januar =0)
int tm_isdst; Sommerzeit (tm_isdst > 0) Winterzeit (tm_istdst == 0) nicht verfügbar (tm_isdst < 0)

Auf Linux-Systemen sind außerdem noch folgende Komponenten vorhanden:

long int tm_gmtoff;

tm_gmtoff gibt die Sekunden östlich von UTC bzw. den negativen Wert westlich von UTC für die Zeitzonen an. UTC steht für Universal Time Clock und dient als Bezeichnung für eine auf der gesamten Erde einheitliche Zeitskala. Die Universal Time ist identisch mit der Greenwich Mean Time (GMT). Diese Angabe kann aber auch unter

long int __tm_gmtoff

vorliegen. Ebenfalls nur bei Linux ist folgende Komponente enthalten:

const char *tm_zone;

Diese Variable enthält den Namen der aktuellen Zeitzone. Diese kann auch in folgender Schreibweise gegeben sein:

const char *__tm_zone;

Galileo Computing - Zum Seitenanfang

21.1.1 Konstanten in der Headerdatei <time.h>  downtop

Folgende zwei Konstanten sind in der Headerdatei <time.h> deklariert:

gp  CLOCKS_PER_SEC – Konstante enthält die Anzahl von clock_t-Einheiten pro Sekunde.
gp  NULL – derselbe NULL-Zeiger, den Sie schon in der Headerdatei <stdio.h> kennen gelernt haben.

Galileo Computing - Zum Seitenanfang

21.1.2 Datums – und Zeitfunktionen in <time.h>  toptop

Die Zeit, mit welcher der Systemkern arbeitet, ist die Anzahl vergangener Sekunden, die seit dem 1. Januar 1970, 00:00:00 Uhr vergangen sind. Diese Zeit wird immer mit dem Datentyp time_t dargestellt und enthält das Datum und die Uhrzeit. Diese Zeit kann mit der Funktion

time_t time(time_t *zeitzeiger);

ermittelt werden. Wird für den Parameter zeitzeiger kein NULL-Zeiger verwendet, befindet sich an dieser Adresse die aktuelle Systemzeit. Hierzu ein kleines Listing, das die Zeit in Sekunden fortlaufend seit dem 1. Januar 1970 um 00:00:00 Uhr mithilfe der Funktion time() ausgibt:

/* time1.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifdef  __unix__
   #define clrscr() printf("\x1B[2J")
#else
   #include <stdlib.h>
   #define clrscr() system("cls")
#endif
int main(void) {
   time_t t;
   time(&t);
   while(1) {
      clrscr();
      printf("%ld\n",t);
      printf("Mit <STRG><C> bzw. <STRG><D> beenden!! ");
      time(&t);
   }
   return EXIT_SUCCESS;
}

Nach dem »Jahr 2000«-Problem steht zum Jahre 2038 das nächste Problem an, sollte bis dahin noch mit 32-Bit-Rechnern gearbeitet werden. Mittlerweile steht – beim Schreiben dieses Textes – die Sekundenzahl bei etwa einer Milliarde. time_t ist als long implementiert. Es gibt also Platz für etwa 2 Milliarden Sekunden. Sicherlich wird dieses Problem wieder im letzten Moment angegangen.

localtime() und gmtime() – Umwandeln von time_t in struct tm

Die Ausgabe der Sekunden als Zeitformat ist nicht gerade originell. Sie könnten jetzt anfangen, Funktionen zu schreiben, mit denen der Rückgabewert der Funktion time() in ein entsprechendes Format umgerechnet wird. Oder Sie verwenden bereits geschriebene Standardfunktionen wie:

struct tm *localtime(time_t *zeitzeiger);
struct tm *gmtime(time_t *zeitzeiger);

Beide Funktionen liefern als Rückgabewert die Adresse einer Zeitangabe vom Typ struct tm. Diese Struktur wurde bereits zu Beginn dieses Kapitels behandelt. Die Funktion localtime() wandelt die Kalenderzeit der Adresse time_t *zeitzeiger in lokale Ortszeit um – unter der Berücksichtigung von Sommer- und Winterzeit. gmtime() dagegen wandelt die Kalenderzeit in die UTC-Zeit um.

Hierzu ein Beispiel, welches die Eingabe eines Geburtsdatums erwartet und anschließend das Alter in Jahren, Monaten und Tagen ausgibt:

/* time2.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct tm *tmnow;
void today(void) {
   time_t tnow;
   time(&tnow);
   tmnow = localtime(&tnow);
   printf("Heute ist der ");
   printf("%d.%d.%d\n",
      tmnow->tm_mday, tmnow->tm_mon + 1, tmnow->tm_year + 1900);
}
int main(void) {
   int tag, monat, jahr;
   unsigned int i=0, tmp;
   printf("Bitte gib Deinen Geburtstag ein!\n");
   printf("Tag : ");
   scanf("%d", &tag);
   printf("Monat : ");
   scanf("%d", &monat);
   printf("Jahr (jjjj) : ");
   scanf("%d", &jahr);
   today();
   if(tmnow->tm_mon < monat) {
      i = 1;
      tmp=tmnow->tm_mon+1-monat;
      monat=tmp+12;
   }
   else {
      tmp=tmnow->tm_mon+1-monat;
      monat=tmp;
   }
   if(monat == 12) {
      monat = 0;
      i = 0;
   }
   printf("Sie sind %d Jahre %d Monate %d Tage alt\n",
      tmnow->tm_year+1900-jahr-i,monat, tmnow->tm_mday-tag);
   return EXIT_SUCCESS;
}

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 21.1   Verwendung der Funktion localtime()

Eine Anmerkung zur if-else-Bedingung im Programm. Diese war erforderlich, damit im Monatsdatum kein negativer Wert zurückgegeben wird, und Sie nicht auf einmal 1 Jahr älter sind.

mktime() – Umwandeln von struct tm zu time_t

Jetzt zum Gegenstück der Funktionen localtime() und gmtime():

time_t mktime(struct tm *zeitzeiger);

Auf diese Weise wird eine Zeit im struct tm-Format wieder umgewandelt in eine Zeit im time_t-Format. Ist die Kalenderzeit nicht darstellbar, gibt diese Funktion –1 zurück. Die echten Werte der Komponenten tm_yday und tm_wday in zeitzeiger werden ignoriert. Die ursprünglichen Werte der Felder, tm_sec, tm_min, tm_hour, tm_mday und tm_mon, sind nicht auf den durch die tm-Struktur festgelegten Bereich beschränkt. Befinden sich die Felder nicht im korrekten Bereich, werden diese angepasst.

Das heißt konkret: Wird z.B. das Datum 38.3.2001 eingegeben, muss die Funktion mktime() dieses Datum richtig setzen. Bei richtiger Rückgabe erhalten Sie entsprechende Werte für tm_yday und tm_wday. Der zulässige Bereich für die Kalenderzeit liegt zwischen dem 1. Januar 1970 00:00:00 und dem 19. Januar 2038 03:14:07.

Ein Beispiel soll zeigen, wie Sie den genauen Wochentag durch diese Funktion ermitteln können:

/* time3.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char *wday[] = {
   "Sonntag", "Montag", "Dienstag", "Mittwoch",
   "Donnerstag", "Freitag", "Samstag", "??????"
};
int main(void) {
   struct tm time_check;
   int year, month, day;
   /* Jahr, Monat und Tag eingeben zum
    * Herausfinden des Wochentags */
   printf("Jahr : ");
   scanf("%d", &year);
   printf("Monat: ");
   scanf("%d", &month);
   printf("Tag  : ");
   scanf("%d", &day);
   /* Wir füllen unsere Struktur struct tm time_check
    * mit Werten */
   time_check.tm_year = year – 1900;
   time_check.tm_mon = month – 1;
   time_check.tm_mday = day;
   /* 00:00:01 Uhr */
   time_check.tm_hour  = 0;
   time_check.tm_min   = 0;
   time_check.tm_sec   = 1;
   time_check.tm_isdst = –1;
   if(mktime(&time_check) == –1)
      time_check.tm_wday = 7;  /* = Unbekannter Tag */
   /* Der Tag des Datums wird ausgegeben */
   printf("Dieser Tag ist/war ein %s\n",
      wday[time_check.tm_wday]);
   return EXIT_SUCCESS;
}

asctime() und ctime() – Umwandeln von Zeitformaten in einen String

Mit zwei Funktionen können die beiden Zeitformen struct tm und time_t in einen String konvertiert werden. Hier die Syntax der beiden:

char *asctime(struct tm *zeitzeiger);
char *ctime(time_t *zeitzeiger);

Auch dazu ein kleines Beispiel in einem Listing:

/* time4.c */
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
   FILE *datei;
   time_t time1;
   struct tm *time2;
   char zeit[25];
   int c;
   if(argc<2) {
      printf("Bitte Eingeben : %s textdatei.txt\n",*argv);
      return EXIT_FAILURE;
   }
   if((datei = fopen(*++argv,"w+")) == NULL) {
      printf("Konnte Datei : %s nicht öffnen!!!!\n",*argv);
      return EXIT_FAILURE;
   }
   printf("Eingabe machen (mit '#' beenden)\n>");
   /* Wir schreiben in unsere Datei und beenden diese
    * mit dem Zeichen '#' */
   while((c=getchar()) != '#')
      putc(c, datei);
   putc('\n', datei);
   /* Zuerst time_t-Format */
   time(&time1);
   printf("Heute ist %s und Sie haben eben die "
          "Datei %s geschlossen\n",ctime(&time1), *argv);
   /* Jetzt struct tm-Format mit asctime() */
   time1=time(NULL);
   time2=localtime(&time1);
   strcpy(zeit,asctime(time2));
   /* Das Datum schreiben wir in die Datei... */
   fprintf(datei,"%s\n",zeit);
   fclose(datei);
   return EXIT_SUCCESS;
}

Dieses Listing gibt zum einen das heutige Datum mit der Funktion ctime() auf dem Bildschirm aus und schreibt den Rückgabewert der Funktion asctime() in eine Textdatei.

difftime() – Differenz zweier Zeiten

Wird eine Differenz zwischen zwei Zeiten benötigt, lässt sich dies mit der folgenden Funktion ermitteln:

double difftime(time_t zeit1, time_t zeit0);

Diese Funktion liefert die Differenz von zeit1 minus zeit0 als double-Wert zurück. Hierzu ein einfaches und kurzes Beispiel:

/* time5.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
   time_t start, stop;
   double diff;
   printf("Einen Augenblick bitte ...\n");
   start=time(NULL);
   while((diff=difftime(stop=time(NULL),start)) != 5);
   printf("%.1f sek. vorbei!!\n",diff);
   return EXIT_SUCCESS;
}

Das Programm wartet fünf Sekunden, bis es einen entsprechenden Text ausgibt. Bei

while((diff=difftime(stop=time(NULL),start)) !=5);

wurde die Funktion time() gleich in der Funktion difftime() ausgeführt. Natürlich ist dies nicht so gut lesbar, aber es erfüllt denselben Zweck wie:

while((diff=difftime(stop,start)) != 5)
   stop=time(NULL);

clock() – Verbrauchte CPU-Zeit für ein Programm

Eine weitere häufig gestellte Frage lautet: Wie kann ich herausfinden, wie lange das Programm schon läuft? Sie können dies mit folgender Funktion herausfinden:

clock_t clock();

Diese Funktion liefert die verbrauchte CPU-Zeit seit dem Programmstart zurück. Falls die CPU-Zeit nicht verfügbar ist, gibt diese Funktion –1 zurück. Wenn Sie die CPU-Zeit in Sekunden benötigen, muss der Rückgabewert dieser Funktion durch CLOCKS_PER_SEC dividiert werden. Beispiel:

/* runtime.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
   clock_t prgstart, prgende;
   int c;
   prgstart=clock();
   printf("Geben Sie etwas ein und beenden Sie mit #\n");
   printf("\n > ");
   while((c=getchar())!= '#')
      putchar(c);
   prgende=clock();
   printf("Die Programmlaufzeit betrug %.2f Sekunden\n",
      (float)(prgende-prgstart) / CLOCKS_PER_SEC);
   return EXIT_SUCCESS;
}

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 21.2   Verbrauchte Zeit eines Programms mit clock() ermitteln

Damit dürfte es Ihnen nicht schwer fallen, die Nutzungsdauer eines Programms herauszubekommen.

strftime() – Umwandeln von struct tm in einen benutzerdefinierten String

Als Nächstes folgt eine Funktion, welche Sie als die sprintf()-Funktion für Zeit- und Datumswerte ansehen können. Die Syntax lautet:

size_t strftime(char *puffer, int maxzeichen,
                const char *format, struct tm *zeitzeiger);

So kann die Kalenderzeit aus struct tm *zeitzeiger in ein entsprechendes Format in die Adresse puffer geschrieben werden. Folgende Umwandlungsvorgaben können Sie dabei verwenden:


Tabelle 21.3   Formatierungszeichen für eine benutzerdefinierte Zeitangabe

Format … wird ersetzt durch … Beispiel
%a Wochenname (gekürzt) Sat
%A Wochenname (ausgeschrieben) Saturday
%b Monatsname (gekürzt) Jan
%B Monatsname (ausgeschrieben) January
%c Entsprechende lokale Zeit- und Datumsdarstellung Sat Jan 22 22:22:22 MET 2003
%d Monatstag (1–31) 22
%H Stunde im 24-Stunden-Format (0–23) 23
%I Stunde im 12-Stunden-Format (1–12) 5
%j Tag des Jahres (1–366) 133
%m Monat (1–12) 5
%M Minute (0–59) 40
%p AM- oder PM-Zeitangabe; Indikator für das 12-Stunden-Format (USA) PM
%S Sekunden (0–69) 55
%U Wochennummer (0–53) (Sonntag als erster Tag der Woche) 33
%w Wochentag (0–6, Sonntag = 0) 3
%W Wochennummer (0–53) (Montag als erster Tag der Woche) 4
%x lokale Datumsdarstellung 02/20/02
%X lokale Zeitdarstellung 20:15:00
%y Jahreszahl (ohne Jahrhundertzahl 0–99) 01 (2001)
%Y Jahreszahl (mit Jahrhundertzahl YYYY) 2001
%Z, %z Zeitzone (gibt nichts aus, wenn Zeitzone unbekannt) MET
%% Prozentzeichen %

Auch hierzu ein Listing, wie diese Angaben verwendet werden können:

/* time6.c */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
   struct tm *zeit;
   time_t sekunde;
   char string[80];
   time(&sekunde);
   zeit = localtime(&sekunde);
   strftime(string, 80,
   "Es ist %H Uhr und %M Minuten (%Z) %A, %B %Y",zeit);
   printf("%s\n",string);
   return EXIT_SUCCESS;
}

Es wird übrigens empfohlen, bei der formatierten Zeitausgabe des Jahres %Y statt %y zu verwenden, um Probleme mit dem Datum ab dem Jahr 2000 zu vermeiden.

Die folgende Grafik soll alle Funktionen, die Sie hier kennen gelernt haben, anhand ihrer Beziehungen zueinander zusammenfassen:

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 21.3   Datums- und Zeitfunktionen im Überblick

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de