lokale Zeit mit std::chrono?



  • Hallo Leute,

    ich habe folgenden abgespeckten Code, den ich gerne ändern möchte:

    #include <iostream>
    #include <string>
    
    std::string currentDateTime()
    {
        time_t     now = time(0);
        struct tm  tstruct;
        char       buf[80];
        tstruct = *localtime(&now);
    
        strftime(buf, sizeof(buf), "%d.%m.%Y - %H:%M:%S", &tstruct);
        return buf;
    }
    

    Es ist eine einfache Funktion, die mir das aktuelle Datum und Uhrzeit zurückgibt. Ich benötige jetzt allerdings Zeitdaten mit höherer Auflösung (<1 ms), daher wollte ich den Inhalt durch std::chrono ersetzen.

    Habe mal folgendes Zwischenergebnis (quick-and-dirty-Version):

    #include <iostream>
    #include <string>
    #include <sstream>
    #include <chrono>
    
    std::string currentDateTime2()
    {
    	auto time 	= std::chrono::high_resolution_clock::now().time_since_epoch();
    
    	auto ns 	= std::chrono::duration_cast<std::chrono::nanoseconds>(time).count();
    	auto us 	= std::chrono::duration_cast<std::chrono::microseconds>(time).count();
    	auto ms 	= std::chrono::duration_cast<std::chrono::milliseconds>(time).count();
    	auto s 		= std::chrono::duration_cast<std::chrono::seconds>(time).count();
    
    	int time_ns = ns % 1000;
    	int time_us = us % 1000;
    	int time_ms = ms % 1000;
    	int time_s = s % 60;
    	int time_m = (s/60) % 60;
    	int time_h = (s/3600) % 24;
    
    	int date_d = 0; //?
    	int date_m = 0; //?
    	int date_y = 0; //?
    
    	stringstream ss;
    
    	ss << std::setw(2) << std::setfill('0') << date_d << ".";   // tag
    	ss << std::setw(2) << std::setfill('0') << date_m << ".";   // monat
    	ss << std::setw(4) << std::setfill('0') << date_y << " - "; // jahr
    
    	ss << std::setw(2) << std::setfill('0') << time_h << ":";   // stunde
    	ss << std::setw(2) << std::setfill('0') << time_m << ":";   // minute
    	ss << std::setw(2) << std::setfill('0') << time_s << ".";   // sekunde
    
    	ss << std::setw(3) << std::setfill('0') << time_ms;         // millisek.
    	ss << std::setw(3) << std::setfill('0') << time_us;         // mikrosek.
    	ss << std::setw(3) << std::setfill('0') << time_ns;         // nanosek.
    
    	//std::cout << ss.str() << endl << endl;
    
    	return ss.str();
    }
    

    Das Problem ist, dass die Zeit in UTC ausgegeben wird. Kann man mit std::chrono irgendwie die lokale Uhrzeit beziehen?
    Noch so nebenbei gefragt... gibt es eine einfache Möglichkeit das Datum aus dem Zeitstempel (now().time_since_epoch()) zu ermitteln oder muss ich das von Hand berechnen 😕 ?

    viele Grüße,
    Martin


  • Mod

    std::ctime?



  • Schau dir dazu am besten mal die Vorträge von Howard Hinnant an (-> youtube).
    Insbesondere ist sein date.h-Header auch ziemlich gut.
    https://github.com/HowardHinnant/date/blob/master/date.h



  • danke. isch schau mir das mal näher an 🙂



  • habe noch eine Möglichkeit gefunden:

    #include <iostream>
    #include <string>
    #include <sstream>
    #include <chrono>
    
    std::string currentDateTime(bool useLocaleTime)
    {
    	auto timeNow = std::chrono::high_resolution_clock::now();
    	auto timeNowEpoch = timeNow.time_since_epoch();
    	time_t time = std::chrono::high_resolution_clock::to_time_t(timeNow);
    
    	struct tm tstruct;
    	if (useLocaleTime == true)
    	{
    		tstruct = *localtime(&time);  // use locale time
    	}
    	else
    	{
    		tstruct = *gmtime(&time);     // use UTC time
    	}
    
    	int time_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(timeNowEpoch).count() % 1000;
    	int time_us = std::chrono::duration_cast<std::chrono::microseconds>(timeNowEpoch).count() % 1000;
    	int time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeNowEpoch).count() % 1000;
    	int time_s = tstruct.tm_sec;
    	int time_m = tstruct.tm_min;
    	int time_h = tstruct.tm_hour;
    
    	int date_d = tstruct.tm_mday;
    	int date_m = tstruct.tm_mon + 1;
    	int date_y = tstruct.tm_year + 1900;
    
    	stringstream ss;
    	ss << std::setw(2) << std::setfill('0') << date_d << ".";   // day
    	ss << std::setw(2) << std::setfill('0') << date_m << ".";   // month
    	ss << std::setw(4) << std::setfill('0') << date_y << " - "; // year
    
    	ss << std::setw(2) << std::setfill('0') << time_h << ":";   // hour
    	ss << std::setw(2) << std::setfill('0') << time_m << ":";   // minute
    	ss << std::setw(2) << std::setfill('0') << time_s << ".";   // second
    
    	ss << std::setw(3) << std::setfill('0') << time_ms;         // millisecond
    	ss << std::setw(3) << std::setfill('0') << time_us;         // microsecond
    	ss << std::setw(3) << std::setfill('0') << time_ns;         // nanosecond
    
    	return ss.str();
    }
    
    Beispielausgabe: 13.12.2016 - 16:04:50.597401801
    

    ggf. hilft es noch jemanden 🙂



  • Für eine Uhr, welche die Uhrzeit misst, nimm system_clock . Für eine Stoppuhr nimm steady_clock . Mir fällt kein portabler Anwendungfall für high_resolution_clock ein. Du möchtest hier also eine system_clock verwenden.



  • ok danke 🙂



  • Biolunar schrieb:

    Mir fällt kein portabler Anwendungfall für high_resolution_clock ein.

    Höher auflösende Stoppuhr?



  • Es kann sein, dass die high_resolution_clock nicht monoton ist, das heißt die Differenz zwischen zwei Aufrufen kann negativ sein. Schlecht für eine Stoppuhr. Und wenn diese clock nun monoton ist, ist sie ungeeignet für eine Wanduhr, da Systemzeitumstellung nicht erfasst werden können. Generell weiß man auch nicht, ob eine andere Uhr als system_clock mit der Systemzeit gemessen wird.

    Man könnte allerdings zur Kompilierzeit feststellen, ob high_resolution_clock monoton ist und sie dann als Stoppuhr verwenden.


Anmelden zum Antworten