example - date c++
C++ ¿Cómo convierto un std:: chrono:: time_point a largo y viceversa (4)
También señalaría que hay dos formas de obtener el número de ms en el punto de tiempo. No estoy seguro de cuál es mejor, los he comparado y ambos tienen el mismo rendimiento, así que supongo que es una cuestión de preferencia. Quizás Howard podría 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();
El primero lee más claramente en mi mente yendo de izquierda a derecha.
Necesito convertir
std::chrono::time_point
desde un tipo
long
(entero de 64 bits).
Estoy empezando a trabajar con
std::chrono
...
Aquí está mi código:
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;
}
Este código se compila, pero no muestra el éxito.
¿Por qué es
dt
diferente de
now
al final?
¿Qué falta en ese código?
como una sola línea:
long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count();
time_point
objetos de punto de tiempo
solo admiten aritmética con otros objetos de punto de
duration
o
duration
.
Tendrá que convertir su unidad
long
a una
duration
de unidades específicas, luego su código debería funcionar correctamente.
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
Este es un gran lugar para
auto
:
auto now = std::chrono::system_clock::now();
Dado que desea traficar con una precisión de
millisecond
, sería bueno seguir adelante y encubrirlo en el
time_point
:
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
now_ms
es un
time_point
, basado en
system_clock
, pero con la precisión de
milliseconds
lugar de la precisión que tenga su
system_clock
.
auto epoch = now_ms.time_since_epoch();
epoch
ahora tiene el tipo
std::chrono::milliseconds
.
Y esta siguiente declaración se convierte esencialmente en un no-op (simplemente hace una copia y no hace una conversión):
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
Aquí:
long duration = value.count();
Tanto en su código como en mi, la
duration
contiene el número de
milliseconds
desde la época de
system_clock
.
Esta:
std::chrono::duration<long> dur(duration);
Crea una
duration
representada con un
long
y una precisión de
seconds
.
Esto
reinterpret_cast
efectivamente los
milliseconds
en
value
en
seconds
.
Es un error lógico.
El código correcto se vería así:
std::chrono::milliseconds dur(duration);
Esta línea:
std::chrono::time_point<std::chrono::system_clock> dt(dur);
crea un
time_point
basado en
system_clock
, con la capacidad de mantener una precisión a la precisión nativa de system_clock (generalmente más fina que milisegundos).
Sin embargo, el valor de tiempo de ejecución reflejará correctamente que se mantiene un número integral de milisegundos (suponiendo mi corrección en el tipo de
dur
).
Sin embargo, incluso con la corrección, esta prueba fallará (casi siempre):
if (dt != now)
Porque
dt
tiene un número integral de
milliseconds
, pero
now
tiene un número integral de tics más fino que un
millisecond
(por ejemplo,
microseconds
o
nanoseconds
).
Por lo tanto, solo en la rara posibilidad de que
system_clock::now()
devuelva un número integral de
milliseconds
pasaría la prueba.
Pero en su lugar puedes:
if (dt != now_ms)
Y ahora obtendrá el resultado esperado de manera confiable.
Poniendolo todo junto:
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, encuentro todo el
std::chrono
demasiado detallado y lo codifico como:
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;
}
Lo que generará de manera confiable:
Success.
Finalmente, recomiendo eliminar los temporales para reducir al mínimo la conversión del código entre
time_point
y el tipo integral.
Estas conversiones son peligrosas, por lo que cuanto menos código escriba al manipular el tipo integral simple, mejor:
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;
}
El principal peligro anterior
no
es interpretar la
time_point
integral_duration
como
milliseconds
en el camino de regreso a un
time_point
.
Una posible forma de mitigar ese riesgo es escribir:
sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};
Esto reduce el riesgo a solo asegurarse de usar
sys_milliseconds
al salir y en los dos lugares al regresar.
Y un ejemplo más: supongamos que desea convertir ay desde una integral que representa la duración que admite
system_clock
(microsegundos,
décimo
de microsegundos o nanosegundos).
Entonces no tiene que preocuparse por especificar milisegundos como se indicó anteriormente.
El código se simplifica 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;
}
Esto funciona, pero si ejecuta la mitad de la conversión (en integral) en una plataforma y la otra mitad (en integral) en otra plataforma, corre el riesgo de que
system_clock::duration
tenga diferentes precisiones para las dos conversiones.