Push-Nachrichten von MacTechNews.de
Würden Sie gerne aktuelle Nachrichten aus der Apple-Welt direkt über Push-Nachrichten erhalten?
Forum>Entwickler>Einstellbare Uhr in C

Einstellbare Uhr in C

andreas_g
andreas_g29.09.2108:58
Liebe Community,

ich sollte folgendes Problem lösen:

Ich benötige ein Programm, das bei der Initialisierung die aktuelle Zeit als UTC speichert. Die Zeit soll anschließend beliebig änderbar sein, in dem eine neue Zeit als UTC von einem externen Programm gesetzt wird. Die geänderte Zeit soll wiederum als UTC gelesen werden können.

Der aktuelle Code (vereinfacht):
#include <sys/time.h>

time_t start_time;
double offset_time;

void time_init(void) 
{
    start_time = time(NULL);
    offset_time = 0.0;
}

void time_write(struct tm *new_time)
{
    time_t new = mktime(new_time);
    time_t old = start_time + offset_time;
    offset_time += (new, old);
}

struct tm *time_read(void)
{
    time_t tmp = start_time + offset_time;
    return gmtime(&tmp);
}

Mit diesem Code lese ich leider nicht, was geschrieben wurde. Es gehen einige Stunden verloren. Findet jemand den Fehler?

Anmerkung: Die zwischen dem Schreiben und Lesen vergangene Zeit habe ich zur Vereinfachung weggelassen. Das ist jedenfalls nicht die Ursache für den "Zeitverlust".
-2

Kommentare

Dirk!29.09.2109:04
Ich kann leider nichts konkretes zu Deinem Code-Problem beitragen, aber ich hoffe Dir ist bewusst, dass es äußerst schwierig ist Funktionen für Zeit und Datum selber zu programmieren. Wo immer möglich, sollte man die Systemroutinen verwenden, da viele Sonderfälle auftreten, mit denen man nicht rechnet:
+1
andreas_g
andreas_g29.09.2109:20
Dirk!
Ich kann leider nichts konkretes zu Deinem Code-Problem beitragen, aber ich hoffe Dir ist bewusst, dass es äußerst schwierig ist Funktionen für Zeit und Datum selber zu programmieren. Wo immer möglich, sollte man die Systemroutinen verwenden, da viele Sonderfälle auftreten, mit denen man nicht rechnet:
time(), mktime(), gmtime() und difftime() sind Systemroutinen. Es geht lediglich darum, die aktuelle Zeit mit einer einstellbaren Zeitdifferenz auszugeben.
0
andreas_g
andreas_g29.09.2109:22
Ich habe gerade bemerkt, dass sich ein Fehler in time_write() eingeschlichen hat (difftime fehlt), den ich im Ausgangspost nicht mehr korrigieren kann. Hier die korrekte Fassung:

#include <sys/time.h>

time_t start_time;
double offset_time;

void time_init(void) 
{
    start_time = time(NULL);
    offset_time = 0.0;
}

void time_write(struct tm *new_time)
{
    time_t new = mktime(new_time);
    time_t old = start_time + offset_time;
    offset_time += difftime(new, old);
}

struct tm *time_read(void)
{
    time_t tmp = start_time + offset_time;
    return gmtime(&tmp);
}
0
Dirk!29.09.2109:28
andreas_g
time(), mktime(), gmtime() und difftime() sind Systemroutinen. Es geht lediglich darum, die aktuelle Zeit mit einer einstellbaren Zeitdifferenz auszugeben.

Ja, aber so „low-level“, dass vermutlich einige der Problemfälle dort noch gar nicht behandelt werden?
Je nachdem wofür du deine einstellbare Zeitdifferenz verwendest, können durchaus einige der im Link angesprochenen Probleme auftreten!
0
pstoehr29.09.2109:42
Hast du da vielleicht auch ein Minimalbeispiel damit man sieht wie die Funktionen verwendet werden?
0
andreas_g
andreas_g29.09.2109:52
pstoehr
Hast du da vielleicht auch ein Minimalbeispiel damit man sieht wie die Funktionen verwendet werden?

Ein in einem Simulator laufendes Betriebssystem liest die Zeit (time_read). Wenn man im Gastsystem die Zeit umstellt, wird die neue Zeit geschrieben (time_write). Diese neue Zeit sollte vom Gastsystem auch wieder korrekt ausgelesen werden können. Das Gastsystem schreibt UTC und erwartet beim Lesen ebenfalls UTC.
0
pstoehr29.09.2110:24
Minimalbeispiel:
Wie sieht der Source-Code für ein einfaches Beispiel aus, bei dem der Fehler auftritt.
0
andreas_g
andreas_g29.09.2111:02
pstoehr
Minimalbeispiel:
Wie sieht der Source-Code für ein einfaches Beispiel aus, bei dem der Fehler auftritt.

void main(void)
{
    struct tm t;
    time_init();
    t = *time_read();
    printf("init: %d", t.tm_hour);
    t.tm_hour++
    printf("modified: %d", t.tm_hour);
    time_write(&t);
    t = *time_read();
    printf("read: %d", t.tm_hour);
}
0
AidanTale29.09.2112:03
Hmm mktime() liefert dir die lokale Zeit und nicht UTC. Stackoverflow sagt timegm() wandelt eine tm Struktur in ein time_t UTC um.
+1
AidanTale29.09.2112:21
Mir ist allerdings nicht ganz klar wozu du den Offset brauchst. Laut deiner initialen Beschreibung sollte es doch reichen die Startzeitvariable jedes Mal beim Schreiben mit der neuen Zeit in time_t zu überschreiben, oder?
+1
pstoehr29.09.2113:19
Und noch was grundsätzliches zur Programmierung:
Wie Dirk schon geschrieben hat, die Programmierung mit ZeitInfos ist nicht so ganz trivial. So ist zum Beispiel der schreibende Zugriff auf Elemente der struct tm definitiv verboten. So ein Statement wie t.tm_hour++; ist einfach verboten, denn man müßte da ja auf einen "Überlauf" der Stundeninfo reagieren, die dann auch auf "höhere Zeitelemente" durchschlagen kann.

Ich würde die Sache mal so angehen, dass ich die Manipulationen immer mit den time_t machen und die dann wieder in eine struct tm umwandeln.
+1
andreas_g
andreas_g29.09.2113:29
AidanTale
Hmm mktime() liefert dir die lokale Zeit und nicht UTC. Stackoverflow sagt timegm() wandelt eine tm Struktur in ein time_t UTC um.

Wenn ich es richtig verstehe, führt mktime() keine Umrechnung der Zeit durch. Setze ich die Werte in der tm Struktur also auf meine Lokalzeit, ist die resultierende time_t ebenfalls Lokalzeit. Nachdem das Gastsystem aber UTC liefert, müsste dann auch die resultierende time_t UTC sein, oder irre ich mich da?

AidanTale
Mir ist allerdings nicht ganz klar wozu du den Offset brauchst. Laut deiner initialen Beschreibung sollte es doch reichen die Startzeitvariable jedes Mal beim Schreiben mit der neuen Zeit in time_t zu überschreiben, oder?

Du hast recht. Im obigen Beispiel wäre diese Vereinfachung möglich. Ich sehe mir das große Programm einmal an und prüfe, ob dort auch auf den Offset verzichtet werden könnte oder ob es für Auswertungen oder Ähnliches zum Einsatz kommt. Allerdings sehe ich keinen Zusammenhang mit meinem Problem.
0
andreas_g
andreas_g29.09.2113:35
pstoehr
Und noch was grundsätzliches zur Programmierung:
Wie Dirk schon geschrieben hat, die Programmierung mit ZeitInfos ist nicht so ganz trivial. So ist zum Beispiel der schreibende Zugriff auf Elemente der struct tm definitiv verboten. So ein Statement wie t.tm_hour++; ist einfach verboten, denn man müßte da ja auf einen "Überlauf" der Stundeninfo reagieren, die dann auch auf "höhere Zeitelemente" durchschlagen kann.

Ich würde die Sache mal so angehen, dass ich die Manipulationen immer mit den time_t machen und die dann wieder in eine struct tm umwandeln.

Das ist nur ein Beispiel zur Veranschaulichung. Das Gastsystem setzt die Werte im Simulator natürlich korrekt.
0
AidanTale29.09.2114:04
andreas_g
Wenn ich es richtig verstehe, führt mktime() keine Umrechnung der Zeit durch. Setze ich die Werte in der tm Struktur also auf meine Lokalzeit, ist die resultierende time_t ebenfalls Lokalzeit. Nachdem das Gastsystem aber UTC liefert, müsste dann auch die resultierende time_t UTC sein, oder irre ich mich da?

Ich benutze das Zeitgeraffel zu selten um ein echter Experte zu sein, aber ich interpretiere die Beschreibung von mtkime so dass die Zeitzone und Sommerzeit berücksichtigt werden. Selbst wenn auf dem System GMT als Zeitzone gewählt ist hast du immer noch das Sommer/Winterzeitproblem.
Sei es drum es gibt ja wie oben erwähnt eine Methode (timegm() als inverse Methode zu gmtime() die du ja schon verwendest), die das alles ignoriert und UTC annimmt. Ist die Zeit damit korrekt?

Prinzipiell bin ich bei pstoehr, ich würde intern wo möglich mit time_t arbeiten und nur bei der Ausgabe in ein anderes Format umwandeln.
0
andreas_g
andreas_g29.09.2114:14
AidanTale
andreas_g
Wenn ich es richtig verstehe, führt mktime() keine Umrechnung der Zeit durch. Setze ich die Werte in der tm Struktur also auf meine Lokalzeit, ist die resultierende time_t ebenfalls Lokalzeit. Nachdem das Gastsystem aber UTC liefert, müsste dann auch die resultierende time_t UTC sein, oder irre ich mich da?

Ich benutze das Zeitgeraffel zu selten um ein echter Experte zu sein, aber ich interpretiere die Beschreibung von mtkime so dass die Zeitzone und Sommerzeit berücksichtigt werden. Selbst wenn auf dem System GMT als Zeitzone gewählt ist hast du immer noch das Sommer/Winterzeitproblem.
Sei es drum es gibt ja wie oben erwähnt eine Methode (timegm() als inverse Methode zu gmtime() die du ja schon verwendest), die das alles ignoriert und UTC annimmt. Ist die Zeit damit korrekt?

Prinzipiell bin ich bei pstoehr, ich würde intern wo möglich mit time_t arbeiten und nur bei der Ausgabe in ein anderes Format umwandeln.

Ich werde das am Abend testen und dann eine Rückmeldung geben. Allerdings scheint timegm() nicht ideal zu sein, was Portierbarkeit betrifft. Das müsste daher plattformabhängig noch implementiert werden (wofür es aber wohl fertige Lösungen gibt).
Die Umwandlung von und zu tm ist deshalb erforderlich, weil das simulierte System eine Real Time Clock verwendet, die in ihren Registern Sekunden, Minuten, Stunden, Monatstage, Monate und Jahre ab 1900 zählt. Daher bekomme ich vom Gastsystem die Zeit in dieser Form geliefert.
0
Marcel Bresink29.09.2114:15
andreas_g
Wenn ich es richtig verstehe, führt mktime() keine Umrechnung der Zeit durch.

Apples Dokumentation sagt da genau das Gegenteil:
The mktime() function interprets the input structure according to the current timezone setting (see tzset(3)). The timegm() function interprets the input structure as representing Universal Coordinated Time (UTC).
+2
andreas_g
andreas_g29.09.2114:47
Marcel Bresink
andreas_g
Wenn ich es richtig verstehe, führt mktime() keine Umrechnung der Zeit durch.

Apples Dokumentation sagt da genau das Gegenteil:
The mktime() function interprets the input structure according to the current timezone setting (see tzset(3)). The timegm() function interprets the input structure as representing Universal Coordinated Time (UTC).

Danke für Rückmeldung! Dann ist das wahrscheinlich der Fehler. Ich werde es wie gesagt später testen und mich mit dem Resultat melden.
0
andreas_g
andreas_g29.09.2120:35
Ich kann bestätigen: mktime() timegm() löst das Problem.

Vielen Dank für alle konstruktiven Beiträge!
+1

Kommentieren

Diese Diskussion ist bereits mehr als 3 Monate alt und kann daher nicht mehr kommentiert werden.