2016-04-06 9 views
0

Ich arbeite an einem Client-Server-Anwendung (unter Linux ausgeführt werden), und einer der Frames, die ich senden, enthalten einen Zeitstempel (dh der Zeitpunkt, zu dem der Rahmen gesendet wird).UTC Timestamp Vergleich

Um meine Anwendung zuverlässig zu machen, habe ich gmtime verwendet, um die Zeit auf dem Client zu produzieren. Ich bin in Belgien, also ist die Stunde der Client-VM jetzt 2 Stunden später als die UTC-Zeit (wegen der Sommerstunde).

Auf der Serverseite, zuerst konvertiere ich die empfangene Zeichenfolge in einen time_t Typ. Ich tue dies, um die difftime Funktion zu verwenden, um zu sehen, ob der Zeitstempel nicht zu alt ist. Dann erzeuge ich einen Zeitstempel (in UTC-Zeit) erneut mit gmtime, und ich konvertiere es in eine time_t.

Ich vergleiche dann die beiden time_t, um den Zeitunterschied zu sehen.

Ich habe ein Problem mit der Umwandlung der Zeit auf der Serverseite. Ich verwende den gleichen Code wie in dem Client, aber das ausgegebene gmtime ist anders ...


Client-Seite: Funktion den Zeitstempel zu erzeugen und exportieren es in einen String (time_str):

std::string getTime() 
    { 
    time_t rawtime; 
    struct tm * timeinfo; 
    char buffer[80]; 

    time (&rawtime);    // Get time of the system 
    timeinfo = gmtime(&rawtime); // Convert it to UTC time 

    strftime(buffer,80,"%d-%m-%Y %H:%M:%S",timeinfo); 
    std::string time_str(buffer); // Cast it into a string 
    cout<<"Time Stamp now (client) : "<<time_str<<endl; 

    return time_str; 
    } 

Und es produices dies (bei 9h33 Ortszeit):

Zeit S stampfen jetzt: 06-04-2016 07:33:30


Server Side: fucntion den Zeitstempel abzurufen, die NEWX Zeitstempel erzeugen, und vergleichen sie:

bool checkTimeStamp(std::string TimsStamp_str, double delay) 
{ 
    cout<<"TimeStamp recieved: "<<TimsStamp_str<<endl; 
    /* Construct tm from string */ 
    struct tm TimeStampRecu; 
    strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu); 
    time_t t_old = mktime(&TimeStampRecu); 

    /* Generate New TimeStamp */ 
    time_t rawtime; 
    struct tm * timeinfo; 
    time (&rawtime); // Get time of the system 
    timeinfo = gmtime(&rawtime); // convert it to UTC time_t 
    time_t t2 = mktime(timeinfo); // Re-Cast it to timt_t struct 
    /* Convert it into string (for output) */ 
     char buffer[80]; 
     strftime(buffer,80,"%d-%m-%Y %H:%M:%S",timeinfo); 
     std::string time_str(buffer); // Cast it into a string 
     cout<<"Time Stamp now (server) : "<<time_str<<endl; 

    /* Comparison */ 
    double diffSecs = difftime(t2, t_old); 
    cout<<diffSecs<<endl; 
    bool isTimeStampOK; 
    if (diffSecs < delay) 
     isTimeStampOK = true; 
    else 
     isTimeStampOK = false; 

return isTimeStampOK; 
} 

und es ergibt dies (bei 9h33 in Belgien):

Timestamp erhielt: 06-04-2016 07:33:30

Time Stamp jetzt (Server): 06-04-2016 08:33:31


Warum ist die Serverzeit (8h33) weder in Lokalzeit (9h33), weder in der UTC-Zeit (7h33)?

Habe ich einen Fehler in seiner Generation gemacht? Ich verstehe nicht, wo, denn das sind die gleichen Code wie auf der Client-Seite ...

+0

Ich habe vergessen zu erwähnen, dass die beiden VMs zur lokalen Zeit, CentOS laufen. – EisenHeim

Antwort

4

Es gibt ein paar Fehler in Ihrem Code, einige Ihrer Fehler, andere nicht. Das größte Problem hier ist, dass die C <time.h> API so schlecht, verwirrend, unvollständig und fehleranfällig ist, dass Fehler wie diese fast obligatorisch sind. Mehr dazu später.

Das erste Problem ist diese Zeile:

struct tm TimeStampRecu; 

Es schafft eine nicht initialisierte tm und dann geht das in strptime. strptime möglicherweise nicht alle Felder von TimeStampRecu ausfüllen. Sie sollten auf Null initialisieren TimeStampRecu wie folgt aus:

struct tm TimeStampRecu{}; 

Nächstes Problem:

strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu); 

Die 12-Stunden-Zeit bezeichnet mit %I ohne AM/PM-Bezeichner nicht eindeutig ist. Ich vermute, das ist nur ein Typ-O, da es der einzige Ort ist, an dem Sie es benutzen.

Nächstes Problem:

gmtime time_t -> tm UTC to UTC 
mktime tm -> time_t local to UTC 

Das heißt, interpretiert mtkime den Eingang tm nach der lokalen Zeit des Computers es läuft. Was Sie brauchen, ist stattdessen:

timegm tm -> time_t UTC to UTC 

Leider timegm nicht Standard-C (oder C++). Glücklicherweise existiert es wahrscheinlich trotzdem auf Ihrem System.

Mit diesen Änderungen wird der Code wie erwartet ausgeführt.


Wenn Sie 11 sind unter Verwendung von C++ gibt es eine sicherere Datum/Zeit-Bibliothek dies hier zu tun (frei/Open-Source):

https://github.com/HowardHinnant/date

Code Hier wird übersetzt Um diese übergeordnete Bibliothek zu verwenden:

0

Ein Zeitstempel ist ein absoluter Wert. Es hängt nicht von Zeitzonen oder DST ab. Sie gibt die Anzahl der Sekunden seit einem festen Zeitpunkt in der Vergangenheit an. Der von time() zurückgegebene Wert ist derselbe, unabhängig von der Zeitzone des Servers.

Ihr Code erzeugt keine Zeitstempel, sondern Daten, die für den menschlichen Verzehr formatiert sind.

Ich empfehle, dass Sie Timestamps intern verwenden und formatieren sie zu Daten, die nur in der Benutzeroberfläche von Menschen lesbar sind. Wenn Sie jedoch Datumsangaben als Zeichenfolgen zwischen verschiedenen Komponenten Ihrer Anwendung übergeben müssen, legen Sie auch die Zeitzone darin ab.

Ich würde der Code wie folgt schreiben (nur Zeitstempel verwendet wird):

// The client side 
time_t getTime() 
{ 
    return time(NULL); 
} 


// The server side 
bool checkTimeStamp(time_t clientTime, double delay) 
{ 
    time_t now = time(NULL); 

    return difftime(now, clientTime) < delay; 
} 

aktualisieren

Wenn Sie Strings verwenden müssen zwischen Client und Server zu kommunizieren, dann alles, was Sie tun müssen, ist Aktualisieren der Formatzeichenfolge, die zum Formatieren der Zeitstempel als Datum verwendet wird (auf dem Client) und Analysieren der Daten auf Zeitstempel (auf dem Server), um die Zeitzone einzubeziehen, die Sie zum Formatieren des Datums verwendet haben.

Das bedeutet, %Z in das Format überall in Ihrem Code hinzufügen. Verwenden Sie "%d-%m-%Y %H:%M:%S %Z". Übrigens, der Code, den Sie jetzt gepostet haben, lautet "%d-%m-%Y %I:%M:%S" im Anruf an strptime() und das bringt Ihnen am Nachmittag ein anderes Problem.

Bemerkung

Ich benutze "%Y-%m-%d %H:%M:%S %Z" immer, weil es eindeutig und locale-unabhängig ist. 06-04-2016 kann als April 6 oder June 4 interpretiert werden, abhängig von der Muttersprache des Lesers.

+0

Ich muss Zeichenfolgen zwischen dem Client und dem Server übergeben. Und um das 'time_t' in einen String zu konvertieren, muss ich eine' struct tm' übergeben, die von 'localtime' oder' gmtime' generiert wird. Und hier kommen die Fehler. – EisenHeim

+0

Ich habe die Antwort mit dem für Ihren Code erforderlichen Update aktualisiert (um weiterhin Strings zu verwenden). – axiac

+0

Ich habe Ihre Änderungen berücksichtigt, aber die Fehler bleiben ... Der am Server generierte Zeitstempel ist 'CEST', aber ** die in diesem Zeitstempel angegebene Stunde ist nicht die MESZ-Zeit ... ** Ich habe Folgendes: '2016-04-06 10:00:25 MESZ ' (wenn um 11:00 MESZ lief) ... – EisenHeim