怎样让C++ 获取当前时间的两种方法(精确到毫秒)

2022年8月29日 | 分类: 【技术】

参考:https://www.cnblogs.com/wxnew/p/6687196.html

1. boost 方法

#include <boost/date_time/posix_time/posix_time.hpp>
std::string now_str1()
{
    // Get current time from the clock, using microseconds resolution
    const boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
    
    // Get the time offset in current day
    const boost::posix_time::time_duration td = now.time_of_day();
    
    //
    // Extract hours, minutes, seconds and milliseconds.
    //
    // Since there is no direct accessor ".milliseconds()",
    // milliseconds are computed _by difference_ between total milliseconds
    // (for which there is an accessor), and the hours/minutes/seconds
    // values previously fetched.
    //
    const long hours  = td.hours();
    const long minutes  = td.minutes();
    const long seconds  = td.seconds();
    const long milliseconds = td.total_milliseconds() - (hours * 3600 + minutes * 60 + seconds) * 1000;
    
    
    char buf[40];
    sprintf(buf, "%02ld:%02ld:%02ld.%03ld",  hours, minutes, seconds, milliseconds);
    return buf;
}

2. 标准库方法

#include <sys/time.h>
using namespace std;
std::string now_str2()
{
    struct timeval tpend;
    gettimeofday(&tpend,NULL);

    int secofday = (tpend.tv_sec + 3600 * 8 ) % 86400;
    int hours = secofday / 3600;
    int minutes = (secofday - hours * 3600 ) / 60;
    int seconds = secofday % 60;
    int milliseconds = tpend.tv_usec/1000;

    char buf[40];
    sprintf(buf, "%02ld:%02ld:%02ld.%03ld",  hours, minutes, seconds, milliseconds);
    return buf;
}

3. chrono

#include <chrono>
using namespace std::chrono;

    time_point<high_resolution_clock> t1 = std::chrono::system_clock::now();
    QThread::usleep(5432);
    time_point<high_resolution_clock> t2 = std::chrono:: system_clock::now();
    cout << "tick count = " << (t2-t1).count() <<endl;

   //微秒
    int64_t elapsed_micro() const
    {
        return duration_cast<chrono::microseconds>(high_resolution_clock::now() - m_begin).count();
    }

参考:https://blog.csdn.net/ai_faker/article/details/117251549

资源:

Date and time utilities
https://en.cppreference.com/w/cpp/chrono

– C++ Reference
http://cplusplus.com/reference/chrono/

简介

在计算机视觉中我们可能经常需要计算一次推理的耗时,来得到确定的FPS,查了很多其他方法,尤其是clock()这个方法对于ms级计时来说也太不准了。这些方法都太古老了,有的还要区分电脑是不是win。终于被我找到了c++11中的标准库–chrono,又准又快!

不想看罗嗦的介绍的同学可以直接看 1.2中 标黄的例子

1.chrono介绍

主要包含如下的几部分

Clocks
system_clock
steady_clock
high_resolution_clock

Duration
duration

Time point
time_point

1.1 Clocks

一个时钟(clock)包含了两部分:时钟原点和时钟节拍。时钟原点通常是 1970-01-01 00:00:00 UTC,一段时间的时钟节拍数除以振动频率,可以得到这段时间的具体时间。

C++ 定义了三种类型的时钟:

std::chrono::system_clock:本地系统的当前时间 (可以调整)
std::chrono::steady_clock:不能被调整的,稳定增加的时间
std::chrono::high_resolution_clock:提供最高精度的计时周期

system_clock 的时间值可以在操作系统内部进行调整,比如在上午九点,把时间改成下午六点,通常用于获取当前时间。

steady_clock 表示过去某个时间点到现在之间的时间,这个时间不能被调整,物理时间增加,它一定增加,而且与系统时间无关(可以是系统重启以来的时间段),最适合于计算程序的耗时时长。

high_resolution_clock 是一个高分辨率时钟,时间刻度最小。在不同的标准库中,high_resolution_clock 的实现不一致,所以官方不建议使用这个时钟,前两个时钟已经能够满足我们日常的使用要求了。

每一个 clock 类中都有确定的 time_point, duration, Rep, Period 类型,这些类型后面都会讲到。

接下来详细介绍前两个时钟。

这两个时钟类都提供了一个静态成员函数 now() 用于获取当前时间,该函数的返回值都是 time_point 类型,system_clock 还另外提供了两个支持系统时间和 std::time_t 相互转换的静态成员函数: to_time_t() 和from_time_t()。

来看一个例子

#include <iostream>
#include <chrono>
#include <thread>
// using namespace std::chrono;

int main() {
    // "start" and "end"'s type is std::chrono::time_point
    std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();
    {   
        std::this_thread::sleep_for(std::chrono::seconds(2));
    }
    std::chrono::time_point<std::chrono::steady_clock> end = std::chrono::steady_clock::now();

    std::chrono::duration<double> elapsed = end - start;
    std::cout << "Elapsed time: " << elapsed.count() << "s" << std::endl;

    return 0;
}

output

2.00009s

可以看到还是很准的。

sleep_for 用于使主线程休眠,休眠时间由 std::chrono::seconds() 控制,std::chrono::duration 后面讲解。可以将 system_clock 改为 steady_clock,得到的结果基本相同。

1.2 Duration

std::chrono::duration也是一个模板类,从名字都可以看出来,它表示一个时间间隔。

template<
    class Rep,
    class Period = std::ratio<1>
> class duration;

使用参数 Rep 和 Period共同表示时间间隔。Rep用于指定数值类型,表示节拍的数量,比如 int,float 等;

Period 属于 std::ratio 类型,表示单位精度,用来计算一个节拍的周期,std::ratio 是一个分数类型的模板类,包含分子(Num)和分母(Denom)两部分。

template<
    std::intmax_t Num,
    std::intmax_t Denom = 1
> class ratio;

通过 Num/Denom 来得到节拍的周期,注意时间单位默认为秒。duration 默认 std::ratio 的分子为 1,std::ratio 默认分母为 1。

这时再来解释之前出现过的语句:

std::chrono::duration<double> elapsed = end - start;
std::cout << "Elapsed time: " << elapsed.count() << "s";

这里定义了一个变量 elapsed,duration 类型为 double,计算节拍周期的分子分母都默认为 1,那么周期就是 1 秒;然后通过 count()函数来得到节拍的个数,所以输出结果为 2.0009。

在 chrono 中预定义了一系列常用的 duration,可以直接使用:

std::chrono::nanoseconds    duration<long long, std::ratio<1, 1000000000>>
std::chrono::microseconds   duration<long long, std::ratio<1, 1000000>>
std::chrono::milliseconds   duration<long long, std::ratio<1, 1000>>
std::chrono::seconds        duration<long long>
std::chrono::minutes        duration<int, std::ratio<60>>
std::chrono::hours          duration<int, std::ratio<3600>>

以 std::chrono::minutes 为例,Period 为 std::ratio<60> 表示分子为 60,分母默认为 1,那么周期就是 60 秒,所以std::chrono::minutes(5)就代表 5 分钟。

这也是刚才上面用到 std::chrono::seconds(2) 的由来,可以看到最小精度为可以达到纳秒级别。

想要将 std::chrono::duration 在不同的精度之间进行转换时,可以使用 std::chrono::duration_cast。

直接输出ms的例子

#include <iostream>
#include <chrono>
#include <ratio>
#include <thread>

int main()
{
    auto t1 = std::chrono::system_clock::now();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    auto t2 = std::chrono::system_clock::now();

    // floating-point duration: no duration_cast needed
    std::chrono::duration<double, std::milli> fp_ms = t2 - t1;

    // integral duration: requires duration_cast
    auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(fp_ms);

    // converting integral duration to integral duration of shorter divisible time unit: no duration_cast needed
    std::chrono::duration<long, std::micro> int_usec = int_ms;

    std::cout << "took " << fp_ms.count() << " ms, "
              << "or " << int_ms.count() << " whole milliseconds "
              << "(which is " << int_usec.count() << " whole microseconds)" << std::endl;
}

得到 fp_ms 和 int_usec 时并没有用 duration_cast,那是因为有两种情况可以不使用 duration_cast,而使用 std::chrono::duration进行隐式类型转换:

当两者的数值类型为整型,且是大单位转小单位(比如秒转毫秒);
当两者的数值类型都是浮点型;

1.2 Time point

std::chrono::time_point是一个表示具体时间点的类模板,可以表示距离时钟原点的时间长度(duration)。

template<
    class Clock,
    class Duration = typename Clock::duration
> class time_point;

其中的 Clock 用来指定要使用的时钟,比如要使用的 system_clock,steady_clock;

Duration 表示从时钟原点开始到现在的时间间隔,可以设置不同的时间计量单位。

time_point 表示一个时间点,通过 time_since_epoch() 函数就可以得到该时间点到时钟原点的时间间隔。

#include <iostream>
#include <chrono>


int main() {
    // now 表示当前时间到时钟原点的毫秒数
    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

    auto elapsed = std::chrono::duration_cast<std::chrono::hours>(now.time_since_epoch());
    std::cout << elapsed.count() << " 小时" << std::endl;
    std::cout << now.time_since_epoch().count() << " 毫秒"<< std::endl;
    return 0;
}

定义 now 时传入system_clock为第一个参数,使用 duration_cast 将毫秒单位转换为小时单位。

time_point 想要进行精度转换,则使用std::chrono::time_point_cast,用法和 duration_cast 相同,区别就在于输出参数从传入 duration 改为 time_point,如下例子所示。

#include <iostream>
#include <chrono>
using namespace std::chrono;

int main() {
    auto t1 = system_clock::now();
    auto t2 = time_point_cast<seconds>(t1);
    std::cout << t1.time_since_epoch().count() << " 毫秒" << std::endl;
    std::cout << t2.time_since_epoch().count() << " 秒" << std::endl;
    return 0;
}

好了,关于 chrono 的常见用法就是这些,无非就是三部分:表示时钟的clock,表示时间间隔的 duration 和表示时间点的 time_point。

当我们想获取系统时钟或者衡量一段代码运行时间时,就可以考虑使用 chrono 。