2015-07-06 17 views
28

Ho bisogno di convertire std::chrono::time_point in e da un tipo long (intero 64 bit). Sto iniziando lavorando con std::chrono ...C++ Come faccio a convertire un std :: chrono :: time_point a long e back

Ecco il mio codice:

int main() 
{ 
    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); 

    auto epoch = now.time_since_epoch(); 
    auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch); 
    long duration = value.count(); 


    std::chrono::duration<long> dur(duration); 

    std::chrono::time_point<std::chrono::system_clock> dt(dur); 

    if (dt != now) 
     std::cout << "Failure." << std::endl; 
    else 
     std::cout << "Success." << std::endl; 
} 

Questo codice viene compilato, ma non mostra il successo.

Perché il dt è diverso da now alla fine?

Cosa manca su quel codice?

+1

Non ho molta familiarità con la libreria chrono, ma credo che devi usare 'std :: chrono :: duration dur' e anche in questo caso potresti ottenere errori di arrotondamento (' std :: chrono :: system_clock' ha probabilmente una risoluzione maggiore di millisecondi). – MikeMB

risposta

67
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); 

Questo è un ottimo posto per auto:

auto now = std::chrono::system_clock::now(); 

Dal momento che si desidera traffico a millisecond precisione, sarebbe bene andare avanti e segreto ad essa nella time_point:

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now); 

now_ms è un time_point, basato su system_clock, ma con la precisione di milliseconds invece di qualsiasi precisione abbia il tuo system_clock.

auto epoch = now_ms.time_since_epoch(); 

epoch ha ora digitare std::chrono::milliseconds. E questa istruzione successiva diventa essenzialmente un no-op (semplicemente fa una copia e non fa una conversione):

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch); 

Qui:

long duration = value.count(); 

Sia il vostro e il mio codice, duration detiene il numero di milliseconds dall'epoca di system_clock.

Questo:

std::chrono::duration<long> dur(duration); 

Crea un duration rappresentato con un long, e una precisione di seconds. Ciò efficacemente reinterpret_cast s milliseconds detenuto in value a seconds. È un errore logico.Il codice corretto sarebbe simile:

std::chrono::milliseconds dur(duration); 

Questa linea:

std::chrono::time_point<std::chrono::system_clock> dt(dur); 

crea un time_point basata su system_clock, con la capacità di tenere una precisione di precisione nativo 's il system_clock (in genere più fine di millisecondi). Tuttavia, il valore di runtime rispecchierà correttamente un numero intero di millisecondi (presupponendo la correzione sul tipo di dur).

Anche con la correzione, questo test (quasi sempre) sicuro se:

if (dt != now) 

Poiché dt detiene un numero intero di milliseconds, ma now detiene un numero intero di zecche sottile di un millisecond (es microseconds o nanoseconds). Pertanto, solo per la rara possibilità che system_clock::now() abbia restituito un numero intero di milliseconds, il test passerà.

Ma si può invece:

if (dt != now_ms) 

E si avrà ora il risultato previsto in modo affidabile.

Mettere tutto insieme:

int main() 
{ 
    auto now = std::chrono::system_clock::now(); 
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now); 

    auto value = now_ms.time_since_epoch(); 
    long duration = value.count(); 

    std::chrono::milliseconds dur(duration); 

    std::chrono::time_point<std::chrono::system_clock> dt(dur); 

    if (dt != now_ms) 
     std::cout << "Failure." << std::endl; 
    else 
     std::cout << "Success." << std::endl; 
} 

Personalmente trovo tutto il std::chrono eccessivamente prolisso e quindi vorrei codificare come:

int main() 
{ 
    using namespace std::chrono; 
    auto now = system_clock::now(); 
    auto now_ms = time_point_cast<milliseconds>(now); 

    auto value = now_ms.time_since_epoch(); 
    long duration = value.count(); 

    milliseconds dur(duration); 

    time_point<system_clock> dt(dur); 

    if (dt != now_ms) 
     std::cout << "Failure." << std::endl; 
    else 
     std::cout << "Success." << std::endl; 
} 

che sarà affidabile di uscita:

Success. 

Infine, consiglio di eliminare i provvisori per ridurre la conversione del codice tra time_point e tipo integrale al minimo. Queste conversioni sono pericolosi, e così il codice meno si scrive manipolare il tipo integrale a nudo il meglio:

int main() 
{ 
    using namespace std::chrono; 
    // Get current time with precision of milliseconds 
    auto now = time_point_cast<milliseconds>(system_clock::now()); 
    // sys_milliseconds is type time_point<system_clock, milliseconds> 
    using sys_milliseconds = decltype(now); 
    // Convert time_point to signed integral type 
    auto integral_duration = now.time_since_epoch().count(); 
    // Convert signed integral type to time_point 
    sys_milliseconds dt{milliseconds{integral_duration}}; 
    // test 
    if (dt != now) 
     std::cout << "Failure." << std::endl; 
    else 
     std::cout << "Success." << std::endl; 
} 

Il pericolo principale di cui sopra è non interpretare integral_duration come milliseconds sulla via del ritorno a una time_point. Un modo possibile per mitigare questo rischio è quello di scrivere:.

sys_milliseconds dt{sys_milliseconds::duration{integral_duration}}; 

Questo riduce i rischi verso il basso per solo fare in modo di utilizzare sys_milliseconds sulla via d'uscita, e nei due posti sulla via del ritorno in

E un altro esempio: supponiamo di voler convertire da un integrale che rappresenta la durata system_clock (microsecondi, 10 th di microsecondi o nanosecondi). Quindi non devi preoccuparti di specificare millisecondi come sopra.Il codice semplifica a:

int main() 
{ 
    using namespace std::chrono; 
    // Get current time with native precision 
    auto now = system_clock::now(); 
    // Convert time_point to signed integral type 
    auto integral_duration = now.time_since_epoch().count(); 
    // Convert signed integral type to time_point 
    system_clock::time_point dt{system_clock::duration{integral_duration}}; 
    // test 
    if (dt != now) 
     std::cout << "Failure." << std::endl; 
    else 
     std::cout << "Success." << std::endl; 
} 

Questo funziona, ma se si esegue la metà la conversione (fuori a integrale) su una piattaforma e l'altra metà (in dal integrale) su un'altra piattaforma, si corre il rischio che system_clock::duration sarà avere precisioni diverse per le due conversioni.

+0

Molto chiaro e utile. Grazie! – Mendes

+1

@ BrentNash: Attento, potrei portarti su. ;-) Sarò al Cppcon 2015 (http://cppcon.org) parlando di questo: http://howardhinnant.github.io/date_v2.html. L'argomento è strettamente correlato al "time_point_cast (ora)" nella mia risposta sopra. Solo la durata è courser: 'time_point_cast (ora)'. –

+0

Errore tipografico nell'ultimo commento: grossolano, non courser. Ottima risposta però. –

-1

time_point objects supporta solo l'aritmetica con altri oggetti time_point o duration.

Dovrai convertire il tuo long in un duration di unità specificate, quindi il tuo codice dovrebbe funzionare correttamente.

+0

Puoi pubblicare un esempio? – Mendes

+0

Entrambi i collegamenti forniti hanno una sezione "Esempio" in basso. –

+0

L'ho compilato, ma c'è qualche errore logico ... Ho modificato il codice originale ... – Mendes

1

Vorrei anche notare che ci sono due modi per ottenere il numero di ms nel punto temporale. Non sono sicuro di quale sia il migliore, li ho confrontati e hanno entrambi le stesse prestazioni, quindi immagino sia una questione di preferenza. Forse Howard potrebbe telefonare:

auto now = system_clock::now(); 

//Cast the time point to ms, then get its duration, then get the duration's count. 
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count(); 

//Get the time point's duration, then cast to ms, then get its count. 
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count(); 

Il primo si legge più chiaramente nella mia mente andando da sinistra a destra.

Problemi correlati