C++ comment convertir un std:: chrono:: Time point en long et retour
j'ai besoin de convertir std::chrono::time_point
et d'un long
type (entier 64 bits). Im commencer le travail avec std::chrono
...
Voici mon code:
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;
}
Ce code compile, mais ne montre pas de succès.
Pourquoi dt
différent now
à la fin?
Ce qui manque sur ce code?
3 réponses
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
C'est un endroit idéal pour les auto
:
auto now = std::chrono::system_clock::now();
puisque vous voulez faire du trafic à millisecond
précision, il serait bon d'aller de l'avant et dissimulée à l'intérieur du time_point
:
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_ms
est un time_point
, basé sur system_clock
, mais avec la précision d' milliseconds
au lieu de n'importe quelle précision votre system_clock
a.
auto epoch = now_ms.time_since_epoch();
epoch
a maintenant le type std::chrono::milliseconds
. Et cette déclaration suivante devient essentiellement un non-op (fait simplement une copie et ne pas faire une conversion):
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
Ici:
long duration = value.count();
Dans les deux de vous et de mon code, duration
contient le nombre de milliseconds
depuis l'époque de system_clock
.
Ceci:
std::chrono::duration<long> dur(duration);
Crée un duration
représenté par un long
, et une précision de seconds
. Ceci effectivement reinterpret_cast
s le milliseconds
tenue value
seconds
. C'est une erreur de logique. Le code correct ressemblerait à:
std::chrono::milliseconds dur(duration);
ce ligne:
std::chrono::time_point<std::chrono::system_clock> dt(dur);
crée un time_point
en fonction de system_clock
, avec la capacité de tenir une précision à l' system_clock
' s Précision native (typiquement plus fine que millisecondes). Cependant, la valeur de temps d'exécution reflétera correctement qu'un nombre intégral de millisecondes est retenu (en supposant que ma correction sur le type de dur
).
même avec la correction, ce test échouera (presque toujours) cependant:
if (dt != now)
Parce que dt
détient une partie intégrante nombre de milliseconds
, mais now
contient un nombre entier de tiques fines qu'un millisecond
(e.g. microseconds
ou nanoseconds
). Ce n'est donc que par une rare chance que system_clock::now()
renvoie un nombre intégral de milliseconds
le test passe.
mais vous pouvez à la place:
if (dt != now_ms)
et vous obtiendrez maintenant un résultat fiable.
Mettre tous ensemble:
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;
}
Personnellement, je trouve tous les std::chrono
trop verbeux et donc je coderais comme:
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;
}
qui produira de façon fiable:
Success.
enfin, je recommande d'éliminer les temporalités pour réduire la conversion du code entre time_point
et de type intégral au minimum. Ces conversions sont dangereuses, et donc le moins de code que vous écrivez en manipulant le type intégral nu le mieux:
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;
}
Le principal danger ci-dessus est interprétation integral_duration
milliseconds
sur le chemin du retour à un time_point
. Une façon possible de d'atténuer ce risque est d'écrire:
sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
Cela réduit le risque jusqu'à faire assurez-vous d'utiliser sys_milliseconds
sur le chemin, et dans les deux endroits sur le chemin du retour.
et un autre exemple: disons que vous voulez convertir en et à partir d'une intégrale qui représente n'importe quelle durée system_clock
supports (microsecondes, 10 th de microsecondes ou nanosecondes). Alors vous n'avez pas à vous soucier de spécifier des millisecondes comme ci-dessus. Le le code simplifie à:
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;
}
Cela fonctionne, mais si vous exécutez la moitié de la conversion (intégrale) sur une plate-forme et l'autre moitié (à partir de l'intégrale) sur une autre plate-forme, vous courez le risque que system_clock::duration
aura des précisions différentes pour les deux conversions.
je voudrais également noter qu'il y a deux façons d'obtenir le nombre de ms dans le point de temps. Je ne sais pas lequel est le mieux, j'ai comparé les deux ont le même rendement, donc je suppose que c'est une question de préférence. Peut-être Howard pourrait-il intervenir:
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();
Le premier on lit plus clairement dans mon esprit, allant de gauche à droite.
time_point
objets ne prendre en charge l'arithmétique qu'avec d'autres time_point
ou duration
objets.
Vous aurez besoin de convertir votre long
duration
d'unités spécifiées, alors votre code devrait fonctionner correctement.