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.
19 Zeitroutinen
19.1 Die Headerdatei <time.h> 

Es folgen einige Standardfunktionen der Headerdatei <time.h>, in denen Routinen für Zeit und Datum deklariert sind. Tabelle 19.1 gibt Ihnen einen kurzen Überblick über die speziellen (primitiven) Datentypen in dieser Headerdatei und ihre Bedeutungen.
Typ | Bedeutung |
size_t |
arithmetischer Datentyp für Größenangaben |
clock_t |
arithmetischer Datentyp für die CPU-Zeit |
time_t |
arithmetischer Datentyp für Datums- und Zeitangaben |
struct tm |
enthält alle zu einer (gregorianischen) Kalenderzeit relevanten Komponenten |
Laut ANSI-C-Standard sollten in der Struktur tm folgende Komponenten enthalten sein:
»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 Coordinated 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 angegeben sein:
const char *__tm_zone;
19.1.1 Konstanten in der Headerdatei <time.h> 

Folgende zwei Konstanten sind in der Headerdatei <time.h> deklariert:
- CLOCKS_PER_SEC – Die Konstante enthält die Anzahl von clock_t-Einheiten pro Sekunde.
- NULL – Das ist derselbe NULL-Zeiger, den Sie schon in der Headerdatei <stdio.h> kennengelernt haben.
19.1.2 Datums- und Zeitfunktionen in <time.h> 

Die Zeit, mit der der Systemkern arbeitet, ist die Anzahl der 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 folgt nun 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; }
Ob es nach dem »Jahr 2000«-Problem zum Jahre 2038 zum nächsten Problem kommt, bleibt noch offen. Bei vielen Rechnern ist time_t als long implementiert, womit Platz für etwa 2 Milliarden Sekunden wäre. Dies wäre im Jahr 2038 erreicht. Der Standard schreibt hier nicht vor, welchen Wert time_t haben soll, und somit ist der Wertebereich von der Implementierung abhängig.
»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(const time_t *zeitzeiger); struct tm *gmtime(const 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, das 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 Monat(e) %d Tag(e) alt\n", tmnow->tm_year+1900-jahr-i,monat, tmnow->tm_mday-tag); return EXIT_SUCCESS; }
Abbildung 19.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« in »time_t«
Kommen wir 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 in eine Zeit im time_t-Format umgewandelt. 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 fehlerhafte 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 Uhr, und dem 19. Januar 2038, 03:14:07 Uhr.
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 sehen Sie die Syntax der beiden:
char *asctime(struct tm *zeitzeiger); char *ctime(const 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 zum anderen den Rückgabewert der Funktion asctime() in eine Textdatei.
»difftime()« – Differenz zweier Zeiten
Wird eine Differenz zwischen zwei Zeiten benötigt, lässt sich diese 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 ermitteln:
clock_t clock(void);
Diese Funktion liefert die verbrauchte CPU-Zeit seit dem Programmstart zurück. Falls die CPU-Zeit nicht verfügbar ist, gibt die 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 19.2 Verbrauchte Zeit eines Programms mit »clock()« ermitteln
Damit dürfte es Ihnen nicht schwerfallen, die Nutzungsdauer eines Programms herauszubekommen.
»strftime()« – »struct tm« in einen benutzerdefinierten String umwandeln
Als Nächstes folgt eine Funktion, die Sie als die sprintf()-Funktion für Zeit- und Datumswerte ansehen können. Die Syntax lautet:
size_t strftime(char * restrict puffer, int maxzeichen, const char * restrict format, struct tm * restrict zeitzeiger);
So kann die Kalenderzeit aus struct tm *zeitzeiger in einem entsprechenden Format in die Adresse puffer geschrieben werden. Folgende Umwandlungsvorgaben können Sie dabei verwenden:
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 |
Thu Jun 11 22:22:22 MET 2009 |
%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/09 |
%X |
lokale Zeitdarstellung |
20:15:00 |
%y |
Jahreszahl (ohne Jahrhundertzahl 0–99) |
09 (2009) |
%Y |
Jahreszahl (mit Jahrhundertzahl YYYY) |
2009 |
%Z, %z |
Zeitzone (gibt nichts aus, wenn Zeitzone unbekannt) |
MET |
%% |
Prozentzeichen |
% |
Hinweis |
Bei einigen Compilern (beispielsweise GNU-GCC) findet man noch mehr von diesen Umwandlungszeichen. Hierzu will ich Sie allerdings auf die entsprechende Manual-Page von strftime() (http://linux.die.net./man/3/striftime) verweisen. |
Hinweis |
Zu strftime() gibt es mit wcsftime() auch noch ein Gegenstück für breite Zeichen. Die Funktion entspricht im Grunde der von strftime(), nur dass der Formatstring ein String mit breiten Zeichen ist. Auch die maximale Länge (zweiter Parameter) ist hierbei die Anzahl der breiten Zeichen und nicht die Anzahl von Bytes. |
Das folgende Listing zeigt, 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.
Abbildung 19.3 fasst alle Funktionen, die Sie hier kennengelernt haben, anhand ihrer Beziehungen zueinander zusammen.
Abbildung 19.3 Datums- und Zeitfunktionen im Überblick
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.