2013-10-15 5 views
5

Ich habe ein 32-Bit Linux System, in dem ich Daten aufzeichnen muss, die mit einem UINT32 zweiten Offset aus einer Epoche von 1901-01- 01 00:00:00.Erstellen eines boost :: posix_time :: ptime Objekts aus einer 64 Bit Ganzzahl zweiter Zähler

Berechnung der Zeitstempel ist für mich ok, als ich die 64-Bit-ticks() Zähler und ticks_per_second() Funktionen verwenden kann, um die Sekunden zu erzeugen, da Epoche wie folgt (I nur zweite Ebene Auflösung erfordern)

const ptime ptime_origin(time_from_string("1901-01-01 00:00:00")); 
time_duration my_utc = microsec_clock::universal_time() - ptime_origin; 
boost::int64_t tick_per_sec = my_utc.ticks_per_second(); 
boost::int64_t tick_count = my_utc.ticks(); 
boost::int64_t sec_since_epoch = tick_count/tick_per_sec; 

Dies funktioniert für mich, da ich weiß, dass als eine vorzeichenlose Integer, die Sekunden zählen nicht die maximale UINT32 Wert (naja, nicht für viele Jahre sowieso).

Das Problem, das ich habe, ist, dass meine Anwendung eine Modbus-Nachricht erhalten kann, die einen UINT32-Wert enthält, für den ich die Hardware- und Systemuhr mit einem ioctl Anruf unter Verwendung RTC_SET_TIME einstellen muss. Dieser UINT32 ist wieder der Offset in Sekunden seit meiner Epoche 1901-01-01 00:00:00.

jetzt Mein Problem ist, dass ich keine Möglichkeit zu erstellen ein ptime Objekt mit 64-Bit-Integer habe - was auf meinem 32-Bit-System den ticks Teil der time_duration Objekte ist privat und ich bin beschränkt long zu verwenden ist nur ein 4-Byte-Ganzzahl mit Vorzeichen, die nicht groß genug ist, um den Sekundenoffset meiner Epoche zu speichern.

Ich habe keine Kontrolle über den Wert der Epoche und so bin ich wirklich ratlos, wie ich mein benötigtes boost::posix_time::ptime Objekt aus den Daten, die ich habe, erstellen kann. Ich kann wahrscheinlich eine schmutzige Lösung erhalten, indem ich harte Sekundenzählungen zu bestimmten Zeitintervallen berechne und eine zusätzliche Epoche benutze, um eine Brücke zu bilden, aber ich frage mich, ob es etwas im boost Code gibt, der mir erlaubt, das Problem vollständig zu lösen Verwenden der Boost-Datetime-Bibliothek. Ich habe alle Dokumente gelesen, die ich finden kann, aber ich kann keinen offensichtlichen Weg sehen, dies zu tun.

EDIT: Ich fand diese Frage im Zusammenhang Convert int64_t to time_duration aber die akzeptierte Antwort für meine Epoche funktioniert NICHT

Antwort

2

Sie time_durations in den maximal zulässigen Schritten anwenden könnten (was std::numeric_limits<long>::max() ist), da das total_seconds Feld beschränkt sich auf long (unterzeichnet).

Hinweis: Ich habe es als int32_t unten formuliert, so dass es noch ordnungsgemäß funktioniert, wenn auf einer 64-Bit-Plattform kompiliert.

Hier ist eine kleine Demonstration:

#include "boost/date_time.hpp" 
#include <iostream> 

using namespace boost::gregorian; 
using namespace boost::posix_time; 

int main() 
{ 
    uint64_t offset = 113ul*365ul*24ul*60ul*60ul; // 113 years give or take some leap seconds/days etc.? 

    static const ptime time_t_epoch(date(1901,1,1)); 
    static const uint32_t max_long = std::numeric_limits<int32_t>::max(); 
    std::cout << "epoch: " << time_t_epoch << "\n"; 

    ptime accum = time_t_epoch; 
    while (offset > max_long) 
    { 
     accum += seconds(max_long); 
     offset -= max_long; 
     std::cout << "accumulating: " << accum << "\n"; 
    } 

    accum += seconds(offset); 
    std::cout << "final: " << accum << "\n"; 
} 

Drucke:

epoch: 1901-Jan-01 00:00:00 
accumulating: 1969-Jan-19 03:14:07 
final: 2013-Dec-04 00:00:00 

anzeigen Live on Coliru

+0

Danke für die Antwort. Ich habe eine ähnliche Sache selbst gemacht, ich habe nur auf eine Lösung mit Boost gehofft, anstatt um die Runden zu kommen. Ich denke, das Fehlen von Antworten deutet darauf hin, dass es keine gibt. Ich akzeptiere deine Antwort, wenn in ein paar Tagen nichts anderes mehr auftaucht. – mathematician1975

+0

Es ist erstaunlich, dass dies im Oktober 2014 in C++ (sogar mit Boost) geschehen muss. Warum wurden diese Typen nicht schon vor 64 Bit umgestellt? –

+0

@DanNissenbaum Ich habe es mit deiner Antwort getestet und es ist viel eleganter! ** [Coliru] (http://coliru.stacked-crooked.com/a/a0be0c728be95b1f) ** – sehe

2

Obwohl boost::posix_time::secondsnicht wenn die Sekunden eine Zahl größer als 32 repräsentieren verwendet werden Bits (Stand Oktober 2014), es tu rns, dass boost::posix_time::millisecondskann leicht verwendet werden (ohne Abhilfen) wie folgt: So

inline std::string convertMsSinceEpochToString(std::int64_t const ms) 
{ 
    boost::posix_time::ptime time_epoch(boost::gregorian::date(1970, 1, 1)); 
    boost::posix_time::ptime t = time_epoch + boost::posix_time::milliseconds(ms); 
    return boost::posix_time::to_simple_string(t); 
} 

einfach Ihre 64-Bit-Sekunden (64-Bit) Millisekunden konvertieren, und Sie sind gut zu gehen!


Hinweis Be/sehr/bewusst Compiler abhängigen Verhalten mit der Kapazität von builting integralen Typen:

uint64_t offset = 113ul*365ul*24ul*60ul*60ul*1000ul; // 113 years give or take some leap seconds/days etc.? 

würde auf GCC oder Clang arbeiten, aber es wäre einfach die Berechnungen in MSVC2013 Überlauf . Sie müssten die Berechnung explizit auf 64 Bits umstellen:

uint64_t offset = uint64_t(113ul)*365*24*60*60*1000; 
Verwandte Themen