chrono

chrono简介

chrono是一个基于模板的面向对象的设计优雅且功能强大的time librarychrono内部定义了三种和时间相关的类型

  • duration一个duration就代表了一个时间段比如2分钟4小时等等。
  • clock: clock的作用就相当于我们日常使用的手表显示时间。chrono内部定义了三种clocksystem clocksteady clockhigh-resolution-clock
  • time pointtime point表示某个特定的时间点。

std::chrono::duration

duratio基本介绍

基本概念

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

类模板 std::chrono::duration 表示时间间隔。

它由 Rep 类型的计次数和计次周期组成其中计次周期是一个编译期有理数常量表示从一个计次到下一个的秒数。

存储于 duration 的数据仅有 Rep 类型的计次数。若 Rep 是浮点数则 duration 能表示小数的计次数。 Period 被包含为时长类型的一部分且只在不同时长间转换时使用。

使用引入

例子用 chorono 库 刻画 5s 的时间间隔

std::chrono::duration<float, std::ratio<2 / 1>> Five_Second = std::chrono::duration<float, ratio<2 / 1>>(2.5);

这里的Rep (计次数类型) 就是float, 这里的计次数 就是 2.5, 这里的 计次周期 就是 2/1 =2 s

时间间隔 = 计次数2.5 * 计次周期2 =5s

  • 它所表示的时间间隔和下面是等价的
std::chrono::duration<int, std::ratio<5 / 1>> Five_Second = std::chrono::duration<int, ratio<5 / 1>>(1);

这里的Rep (计次数类型) 就是int, 这里的计次数 就是 1, 这里的 计次周期 就是 5/1 =5 s

时间间隔 = 计次数1 * 计次周期5 =5s

std::ratio 参数深入

duration的声明包含两个模板参数第一个模板参数是C++的原生数值类型如long, long long等代表了duration的数值部分。第二个模板参数_Period又是一个模板类std::ratio它的定义如下

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

namespace chrono {

    // ratio以模板的方式定义了有理数比如ratio<1,60>就表示有理数 ‘1/60’
    // _Num代表 'numerator'分子
    // _Den代表 'denominator'分母
    template<intmax_t _Num, intmax_t _Den = 1>
    class ration {
    
        // 求__Num的绝对值
        static constexpr const intmax_t __na = __static_abs<_Num>::value;
    
        // 求_Den的绝对值
        static constexpr const intmax_t __da = __static_abs<_Den>::value;
    
        // __static_sign的作用是求符号运算
        static constexpr const intmax_t __s = __static_sign<_Num>::value * __static_sign<_Den>::value;
    
        // 求分子、分母的最大公约数
        static constexpr const intmax_t __gcd = __static_gcd<__na, __da>::value;
    
    public:
    
        // num是化简后的_Num
        static constexpr const intmax_t num = __s * __na / __gcd;
    
        // den是化简后的_Den
        static constexpr const intmax_t den = __da / __gcd;
    };
}

ratio用两个整数型模板参数来表示一个有理数的分子和分母部分比如ratio<1, 1000>就表示有理数0.001。理解了这一点我们再来看duration的定义

template<class _Rep, class _Period = ratio<1> > class duration 

ratio在这里的确切含义为以秒为单位的放大倍率比如ratio<60, 1>表示一个1秒的60倍也就是1分钟ratio<1, 1000>表示1秒的千分之一倍也就是1毫秒。所以duration<long, ratio<60, 1>>就定义了一个类型为longduration而这个duration的单位为“分钟”。

特化的duratio

  • chrono中宏定义了许多特例化了的duration

    就是常见的hoursminiutessecondsmilliseconds等使用std::chrono::milliseconds直接使用

namespace chrono {

    // 1nano = 1/1,000,000,000 秒
    typedef ratio<1LL, 1000000000LL> nano;

    // 1micro = 1/1,000,000秒
    typedef ratio<1LL, 1000000LL> micro;

    // 1milli = 1/1,000秒
    typedef ratio<1LL, 1000LL> milli;

    // 1centi = 1/100秒
    typedef ratio<1LL, 100LL> centi;

    // 1kilo = 1,000秒
    typedef ratio<1000LL, 1LL> kilo;

    // 1mega = 1,000,000秒
    typedef ratio<1000000LL, 1LL> mega;
    
    // ...
    
    typedef duration<long long,         nano> nanoseconds;  // nanosecond是duration对象 nano 是 ratio对象
    typedef duration<long long,        micro> microseconds;
    typedef duration<long long,        milli> milliseconds;
    typedef duration<long long              > seconds;
    typedef duration<     long, ratio<  60> > minutes;
    typedef duration<     long, ratio<3600> > hours;
    
    // ...
}

改造之前的代码

例子用 chorono 库 刻画 5s 的时间间隔

std::chrono::seconds Five_Second = std::chrono::seconds(5); // 这里的seconds 就是 特化的duration

静态成员函数 count

原型

constexpr rep count() const;

std::chrono::duration<Rep,Period>::count

  • 返回值

此 duration 的计次数。

例子

#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
int main(int argc, char **argv)
{
    std::chrono::seconds Five_Second = std::chrono::seconds(5);
    cout << "Five_seconds的计次数为:: " << Five_Second.count() << endl;
}

Five_seconds的计次数为:: 5



构造函数

void func(std::chrono::seconds d)
{
    cout << "d的计次数为:: " << d.count() << endl;
}

int main(int argc, char **argv)
{
    // std::chrono::seconds Five_Second = std::chrono::seconds(5);
    // cout << "Five_seconds的计次数为:: " << Five_Second.count() << endl;

    // todo1  构造函数
    std::chrono::seconds Five_Second1;     // 未初始化
    std::chrono::seconds Five_Second2{};   // 零初始化
    std::chrono::seconds Five_Second3{5};  // ok 5s
    std::chrono::seconds Five_Second3(5s); // ok 5s
                                           // todo2 不允许隐式类型转换
    //  std::chrono::seconds Five_Second3 = 5; // error 不允许隐式类型转换
    //  func(5);                               // error 不允许隐式类型转换
    func(5s); // ok  5s
}

支持加减乘除运算

  • 这里的seconds 就是特化的 duration
    void func(std::chrono::seconds d)
    {
        cout << "d的计次数为:: " << d.count() << endl;
    }
    void func2()
    {
        auto x = 3s;
        x += 2s;
        func(x);
        x = x - 5s;
        //    x+=5;//error     不能加 int 
        func(x);
    }
    // d的计次数为::5 d的计次数为::0

编译细节

比较编译器所花费时间

  • code1
std::chrono::seconds func(std::chrono::seconds d1,std::chrono::seconds d2)
{
    return d1+d2;
}
  • code 2
int64_t func(int64_t x1,int64_t x2)
{
	return x1+x2;
}

image-20230116170306752

  • 实际上他们的汇编代码是相同的除了顶部名称修改

  • 不仅仅局限在此下面代码的运算也是相同的

image-20230116172250075

image-20230116172316654

支持比较运算符

namespace detail2
{
    constexpr auto time_limit = 5s;
    void fun(std::chrono::seconds s)
    {
        if (s == time_limit)
        {
            cout << "equal time" << endl;
        }
        else if (s <= time_limit)
        {
            cout << "in time" << endl;
        }
        else
        {
            cout << "out of time" << endl;
        }
    }
}
 	detail2::fun(1s);
    detail2::fun(5s);
    detail2::fun(6s);
in time
equal time
out of time

查询范围

image-20230116171011768

  auto max = std::chrono::seconds::max();

    auto min = std::chrono::seconds::min();
    cout << "max = " << max.count() << endl;
    cout << "min = " << max.count() << endl;

类型转换

例子引入

  • 一般来说: 如果一个 < chrono > 转换是无损的那么它是隐式的。如果一个转换不是无损的它不会在没有特殊语法的情况下编译。
  • 如果转换会带来精度损失编译就会报错。如果一定需要这样的转换就要进行explicitly明确的的转换
namespace detail
{
    void func()
    {

        auto time_day = 24h;
        auto time_seconds = std::chrono::seconds(time_day);
        cout << time_seconds.count() << endl;
    }
    // void func2()
    // {

    //     auto time_seconds = 86400s;
    //     auto time_day = std::chrono::hours(time_seconds);
    //     // chrono 库不支持 将 duration(持续时间)类型从更精确的类型转换为不太精确的类型
    //     cout << time_day.count() << endl;
    // }
    void func3()
    {

        auto time_seconds = 86400s;
        auto time_day = std::chrono::duration_cast<std::chrono::hours>(time_seconds);

        cout << time_day.count() << endl;
    }
      void func4()
    {
        auto mi = std::chrono::milliseconds{3400ms};
        std::chrono::seconds s = std::chrono::duration_cast<std::chrono::seconds>(mi);
        cout << s.count() << endl;
    }

}
int main(int argc, char **argv)
{
    // 初步认识 duration_cast()强制转换

    detail::func();    // 这里没有损失精度

    // detail::func2(); // error
    detail::func3();  // 这里没有损失精度+
    
    detail::func4();  //输出 3 s ,损失精度
    
    
}

修改seconds的范围

  • 如果觉得64bit表示seconds太浪费<chrono>还提供下面的方法依然可以像上面的那些duration那样互转。
using seconds32 = std::chrono::duration<int32_t>;
  • 甚至下面这个也能工作
using seconds32 = std::chrono::duration<uint32_t>;
  • 甚至下面这个也能工作(使用“safeint”库)
using seconds32 = std::chrono::duration<safe<uint32_t>>;
  • 甚至下面这个也能工作(使用浮点类型)
using fseconds = std::chrono::duration<float>;

浮点类型

对于浮点表示形式可以从任何精度进行隐式转换而不需要使用 period _ cast。其基本原理是没有截尾误差(只有舍入误差)。所以隐式转换是安全的。

原始的毫秒

 typedef ratio<1LL, 1000LL> milli;
 using my_ms = std::chrono::duration<double, std::milli>; // double 也可以用float代替
    void myf(my_ms d)
    {
        cout << "my_ms:: " << d.count() << " ms\n";
    };

    void f(std::chrono::milliseconds d)
    {
        cout << "f::" << d.count() << " ms\n";
    };

    void func()
    {
        // f(45ms + 63us);//原始的毫秒不支持隐式类型转换
       
        myf(45ms + 63us); // 45.063 ms
    }

系统特化的duratio

 typedef ratio<1LL, 1000000000LL> nano;

    // 1micro = 1/1,000,000秒
    typedef ratio<1LL, 1000000LL> micro;

    // 1milli = 1/1,000秒
    typedef ratio<1LL, 1000LL> milli;

    // 1centi = 1/100秒
    typedef ratio<1LL, 100LL> centi;

    // 1kilo = 1,000秒
    typedef ratio<1000LL, 1LL> kilo;

    // 1mega = 1,000,000秒
    typedef ratio<1000000LL, 1LL> mega;
typedef duration<long long, nano> nanoseconds; // 纳秒 
typedef duration<long long, micro> microseconds; // 微秒 
typedef duration<long long, milli> milliseconds; // 毫秒 
typedef duration<long long> seconds; // 秒 
typedef duration<int, ratio<60> > minutes; // 分钟 
typedef duration<int, ratio<3600> > hours; // 小时 

自定义单位转换

#include <iostream> 
#include <chrono> 
 
typedef std::chrono::duration<float, std::ratio<3, 1> > three_seconds; 
typedef std::chrono::duration<float, std::ratio<1, 10> > one_tenth_seconds; 
 
int main() 
{ 
    three_seconds s = std::chrono::duration_cast<three_seconds>(one_tenth_seconds(3)); 
    std::cout << "3 [1/10 seconds] equal to " << s.count() << " [3 seconds]\n"; 
    std::cin.get(); 
} 

自定义 duration ,提高精度

  • 这里就是使用了上面的浮点类型
namespace detail2
{


    int work()
    {
        int sum = 0;
        for (int i = 0; i < 1e8; ++i)
            sum += i * i;
        return sum;
    }

    void func()
    {
        auto start = std::chrono::steady_clock::now();
        volatile int result = work();
        auto finish = std::chrono::steady_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
        std::cout << duration.count() << "ms" << std::endl;
    }

    /*
todo 但是这样只能输出整数毫秒如果想要更精确一点一种方法是转换成microseconds以后除以1000.0
todo 更优雅地可以自己定义一种时间段类型如duration<double, milli>其中double表示这种时间段类型用double来存储时钟周期数量milli表示时钟周期为1ms。
todo 从由整数表示的duration到由浮点数表示的duration的转换可以由duration的构造函数来完成无需再用duration_cast

*/
    // 自定义时间段类型提高精度
    void func2()
    {
        auto start = std::chrono::steady_clock::now();
        volatile int result = work();
        auto finish = std::chrono::steady_clock::now();
        using myduration = std::chrono::duration<double, std::milli>;
        myduration md = (finish - start);
        // auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
        std::cout << md.count() << "ms" << std::endl;
    }
}

duratio源码补充

std::chrono::duration是一个模板类关键代码摘录如下格式有调整

template<class _Rep, class _Period> 
class duration { 
public: 
    typedef duration<_Rep, _Period> _Myt; 
    typedef _Rep rep; 
    typedef _Period period; 
     
    // constructor, save param to _MyRep, used by count() member function. 
    template<class _Rep2, 
    class = typename enable_if<is_convertible<_Rep2, _Rep>::value 
        && (treat_as_floating_point<_Rep>::value || !treat_as_floating_point<_Rep2>::value), 
        void>::type> 
    constexpr explicit duration(const _Rep2& _Val) 
        : _MyRep(static_cast<_Rep>(_Val)) 
    { 
    } 
         
    constexpr _Rep count() const { return (_MyRep);	} 
}; 
 
// convert duration from one unit to another. 
template<class _To, class _Rep, class _Period> inline 
constexpr typename enable_if<_Is_duration<_To>::value, _To>::type 
duration_cast(const duration<_Rep, _Period>& _Dur) 
{ 
typedef ratio_divide<_Period, typename _To::period> _CF; 
 
typedef typename _To::rep _ToRep; 
typedef typename common_type<_ToRep, _Rep, intmax_t>::type _CR; 
 
#pragma warning(push) 
#pragma warning(disable: 6326)	// Potential comparison of a constant with another constant. 
return (_CF::num == 1 && _CF::den == 1 
        ? static_cast<_To>(static_cast<_ToRep>(_Dur.count())) 
    : _CF::num != 1 && _CF::den == 1 
        ? static_cast<_To>(static_cast<_ToRep>( 
            static_cast<_CR>( 
                _Dur.count()) * static_cast<_CR>(_CF::num))) 
    : _CF::num == 1 && _CF::den != 1 
        ? static_cast<_To>(static_cast<_ToRep>( 
            static_cast<_CR>(_Dur.count()) 
                / static_cast<_CR>(_CF::den))) 
    : static_cast<_To>(static_cast<_ToRep>( 
        static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num) 
            / static_cast<_CR>(_CF::den)))); 
#pragma warning(pop) 
} 

radio 源码补充

std::ratio是一个模板类关键代码摘录如下格式有调整

template<intmax_t _Nx,	intmax_t _Dx = 1> 
struct ratio 
{ 
    static_assert(_Dx != 0,	"zero denominator"); 
    static_assert(-INTMAX_MAX <= _Nx, "numerator too negative"); 
    static_assert(-INTMAX_MAX <= _Dx, "denominator too negative"); 
 
    static constexpr intmax_t num = _Sign_of<_Nx>::value 
        * _Sign_of<_Dx>::value * _Abs<_Nx>::value / _Gcd<_Nx, _Dx>::value; 
 
    static constexpr intmax_t den = _Abs<_Dx>::value / _Gcd<_Nx, _Dx>::value; 
 
    typedef ratio<num, den> type; 
}; 

第一个参数_Nx代表了分子第二个参数 _Dx代表了分母。
num是计算后的分子den是计算后的分母。在duration转换的时候会用到这两个值。

注这里的计算是指约分可以看到传入的分子和分母都除以了最大公约数。

numnumerator的缩写表示分子。
dendenominator的缩写表示分母。


duration_cast()分析

  • 注明这个函数是在duration 源码中的

函数duration_cast()提供了在不同的时间单位之间进行转换的功能。

duration_cast()主要分为两部分

  • 通过ratio_divide定义了从一个ratio转换到另外一个ratio的转换比例。
    比如1/102/5的转换比例是1/4 (1/10/(2/5)) = 1/4也就是说一个1/10相当于1/42/5
    对应到代码里就是_CF::num = 1, _CF::den = 4.
  • 根据转换比例把n个单位的原数据转换到目标数据return语句
    return语句写的这么复杂是为了效率避免不必要的乘除法当分子是1的时候没必要乘当分母是1的时候没必要除。
    简化一下去掉了强制类型转换就是
    return _Dur.count() * (_CF::num / _CF::den);

通俗点讲如果AB的转换比例是num/den那么1A可以转换为num/denB, nA可以转换为 n * (num/den)B

例子重要
#include <iostream>   
#include <chrono>   
int main()  
{  
    std::chrono::milliseconds mscond(1000); // 1 second   
    std::cout << mscond.count() << " milliseconds.\n";   //1000
  
    // 时间间隔 = `计次数(count)`   * `计次周期ration` 
    std::cout << mscond.count() * std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den;     // 1000* 1/1000
    std::cout << " seconds.\n";  
    system("pause");  
    return 0;  
}  

这里的需要注意的是 std::chrono::milliseconds::period::numstd::chrono::milliseconds::period::den

拆开来理解

std::chrono::milliseconds 是 duration 模板类的特化也就是 duration类 , 在duration 类 的成员中有如下成员

 typedef duration<_Rep, _Period> _Myt; 
    typedef _Rep rep; 
    typedef _Period period; 

所以 std::chrono::milliseconds::period 就是 引用duration中的 period成员 接着看下面duration的类模版声明

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

其中 period 是 _Period 类型的 也就是 ratio<> 类型的所以 period 就相当于 是 ratio 类型对象 再结合一下ratio源码中存在两个成员 num 和 den .

就不难得出std::chrono::milliseconds::period::num / std::chrono::milliseconds::period::den 是 milliseconds duration的 ratio 计数周期 也就是 1/1000 【关键】

​ 注ratio 源码部分

   static constexpr intmax_t num = _Sign_of<_Nx>::value 
        * _Sign_of<_Dx>::value * _Abs<_Nx>::value / _Gcd<_Nx, _Dx>::value; 
 
    static constexpr intmax_t den = _Abs<_Dx>::value / _Gcd<_Nx, _Dx>::value; 
 
    typedef ratio<num, den> type; 

预定义的 radio

为了方便代码的书写标准库提供了如下定义

TypeDefinition
yoctostd::ratio<1, 1000000000000000000000000>, if std::intmax_t can represent the denominator
zeptostd::ratio<1, 1000000000000000000000>, if std::intmax_t can represent the denominator
attostd::ratio<1, 1000000000000000000>
femtostd::ratio<1, 1000000000000000>
picostd::ratio<1, 1000000000000>
nanostd::ratio<1, 1000000000>
microstd::ratio<1, 1000000>
millistd::ratio<1, 1000>
centistd::ratio<1, 100>
decistd::ratio<1, 10>
decastd::ratio<10, 1>
hectostd::ratio<100, 1>
kilostd::ratio<1000, 1>
megastd::ratio<1000000, 1>
gigastd::ratio<1000000000, 1>
terastd::ratio<1000000000000, 1>
petastd::ratio<1000000000000000, 1>
exastd::ratio<1000000000000000000, 1>
zettastd::ratio<1000000000000000000000, 1>, if std::intmax_t can represent the numerator
yottastd::ratio<1000000000000000000000000, 1>, if std::intmax_t can represent the numerator
改写例子中的代码

结合预定义的radio

#include <iostream>
#include <chrono>
using namespace std;
int main()
{
    std::chrono::milliseconds mscond(1000);            // 1000ms
    std::cout << mscond.count() << " milliseconds.\n"; // 1000

    // 时间间隔 = `计次数(count)`   * `计次周期ration`
    std::milli mi;

    std::cout << mscond.count() * mi.num / mi.den; // 1000* 1/1000
    // cout << "mi.num" << mi.num << "mi.den" << mi.den << endl;

    std::cout
        << " seconds.\n";

    return 0;
}

duration其他算术运算补充

下图列出了duration可以进行的算术运算。例如

  • 你可以计算两个duration的和、差、积和商
  • 你可以加减tick或加减其他duration
  • 你可以比较两个duration的大小

img

运算所涉及的两个duration的单位类型可以不同

  • 标准库的common_type<>为duration提供了一个重载版本
  • 因此运算所得的那个duration其单位将是两个操作数的单位的最大公约数****演示案例
std::chrono::seconds      d1(42); //42秒

std::chrono::milliseconds d2(10); //10毫秒

d1 - d2; //返回41990个毫秒为单位的一个duration42000-10=41990

d1 < d2; //返回false
std::chrono::duration<int, std::ratio<1, 3>> d3(1); //1/3秒
std::chrono::duration<int, std::ratio<1, 5>> d4(1); //1/5秒
d3 + d4; //返回8/15秒1/3+1/5=8/15
d3 < d4; //返回false

Duration的其他操作

  • 下面列出了duration支持的其它操作

img

  • duration的默认构造函数会以默认方式初始化其数值因此基础类型的初值是不明确的
  • duration提供三个静态函数zero()产出一个0秒durationmin()和max()分别产出一个duration所能拥有的最小值和最大值
  • 例如下面为duration对象添加一个operator<<版本

template<typename V,typename R>
std::ostream& operator<<(std::ostream& s, const std::chrono::duration<V, R>& d)
{
    s << "[" << d.count() << " of " << R::num << "/" << R::den << "]";
    return s;
}
 
int main()
{
    std::chrono::milliseconds d(42);
    std::cout << d << std::endl;

duration_cast<>

  • 在上面我们介绍过duration的类型转换可以将一个低精度的单位类型转换为一个高精度的单位类型例如将分钟转换为秒将秒转换为微秒但是不能将一个高精度的单位类型转换为一个低精度的单位类型例如将微秒转换为秒将秒转换为分钟等。因为这可能会造成数据的丢失例如将42010毫秒转换为秒结果是42那么原本的10毫秒就丢失了
  • *如果想要将高精度的单位类型转换为一个低精度的单位类型那么可以使用duration_cast<>进行强制转换*
  • 例如
std::chrono::seconds sec(55);

//错误的默认不能将秒转换为分钟

std::chrono::minutes m1 = sec;

//正确的可以使用duration_cast将秒转换为分钟

std::chrono::minutes m2 = std::chrono::duration_cast<std::chrono::minutes>(sec);
  • 将浮点数类型的duration转换为整数类型的duration也需要使用duration_cast<>。例如
std::chrono::duration<double, std::ratio<60>> halfMin(0.5);

//错误halfMin的tick为double类型s1的tick默认为int类型

std::chrono::seconds s1 = halfMin;

//正确使用duration_cast强制转换

std::chrono::seconds s2 = std::chrono::duration_cast<std::chrono::seconds>(halfMin)
  • 演示案例
    • 下面代码把duration切割为不同单元例如让一个以毫秒为单位的duration切割为相对应的小时、分钟、秒钟、毫秒
    • 在下面我们将ms转换为小时hh实际数值会被截断而四舍五入
    • 幸好有%运算符我们可以把一个duration当做其第二实参于是写下ms%std::chrono::hours(1)轻松处理剩余的毫秒那么毫秒又被转换为分钟
std::chrono::milliseconds ms(7255042);
 
std::chrono::hours hh = std::chrono::duration_cast<std::chrono::hours>(ms);
std::chrono::minutes mm = std::chrono::duration_cast<std::chrono::minutes>(ms%std::chrono::hours(1));
std::chrono::seconds ss = std::chrono::duration_cast<std::chrono::seconds>(ms%std::chrono::minutes(1));
std::chrono::milliseconds msec = std::chrono::duration_cast<std::chrono::milliseconds>(ms%std::chrono::seconds(1));
 
std::cout << "raw: " << hh << "::" << mm << "::" << ss << "::" << msec << std::endl;
std::cout << "     " << setfill('0') << setw(2) << hh.count() << "::"
                                     << setw(2) << mm.count() << "::"
                                     << setw(2) << ss.count() << "::"
                                     << setw(3) << msec.count() << std::endl;

img

rs(1)轻松处理剩余的毫秒那么毫秒又被转换为分钟

std::chrono::milliseconds ms(7255042);
 
std::chrono::hours hh = std::chrono::duration_cast<std::chrono::hours>(ms);
std::chrono::minutes mm = std::chrono::duration_cast<std::chrono::minutes>(ms%std::chrono::hours(1));
std::chrono::seconds ss = std::chrono::duration_cast<std::chrono::seconds>(ms%std::chrono::minutes(1));
std::chrono::milliseconds msec = std::chrono::duration_cast<std::chrono::milliseconds>(ms%std::chrono::seconds(1));
 
std::cout << "raw: " << hh << "::" << mm << "::" << ss << "::" << msec << std::endl;
std::cout << "     " << setfill('0') << setw(2) << hh.count() << "::"
                                     << setw(2) << mm.count() << "::"
                                     << setw(2) << ss.count() << "::"
                                     << setw(3) << msec.count() << std::endl;

[外链图片转存中…(img-fnykkV5i-1673943125857)]

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6