std::chrono时间库详解

本文介绍C++中使用std::chrono库进行时间日期处理的方法,包括时间单位定义、时间戳操作、时间间隔计算及时间格式化等核心功能。

主要时间类型

std::ratio<num, den> 定义分式(std::ratio模板请参考《C++新标准之std::ratio》),例如:

    std::ratio<60, 1> minutes;//<分子,分母>一分钟60秒
    std::ratio<60 * 60> hource;//1小时3600秒
    std::ratio<1, 1000> milliseconds; //1ms是1/1000秒

chrono命名空间定义好的时间单位

   typedef duration <Rep, ratio<3600,1>> hours;
   typedef duration <Rep, ratio<60,1>> minutes;
   typedef duration <Rep, ratio<1,1>> seconds;
   typedef duration <Rep, ratio<1,1000>> milliseconds;
   typedef duration <Rep, ratio<1,1000000>> microseconds;
   typedef duration <Rep, ratio<1,1000000000>> nanoseconds;
  • 使用举例:
    chrono::minutes mintu{2};//2分钟
    chrono::seconds sec{3};//3秒钟
    chrono::milliseconds mills{500};//500毫秒
    auto dul = sec - mills;//两者差值,单位默认转到更小的 2500ms
    dul.count(); //值为2500
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); //当前线程休眠100毫秒
  • chrono::duration_cast<>() 时间单位转换
chrono::duration_cast<chrono::seconds>(mintu).count(); //2分钟换算为120秒 

获取当前时间

time_point 表示一个时间点

  • 获取当前时间
chrono::system_clock::time_point now = chrono::system_clock::now();//当前时间time_point格式

 std::time_t oldTime = time(nullptr);//c函数获取当前时间
 cout << "oldTime = " << oldTime << endl;
 chrono::system_clock::time_point timePoint = chrono::system_clock::now();//stl库获取当前时间
 std::time_t newTime = chrono::system_clock::to_time_t(timePoint);//转换为旧式接口,单位:秒
 cout<<"newTime = " << newTime <<endl;// oldTime == timeT
  • 格式化打印当前时间
/*  chrono::system_clock::time_point与std::time_t类型可相互函数
 *  chrono::system_clock::to_time_t()   
 *  chrono::system_clock::from_time_t()     
 */
std::time_t nowTime = chrono::system_clock::to_time_t(now);//转换为 std::time_t 格式 
std::put_time(std::localtime(&nowTime), "%Y-%m-%d %X"); // 2019-06-18 14:25:56

std::put_time用法请参考《std::put_time

  • std::localtime非线程安全,使用localtime_r函数代替
struct tm cutTm = {0};
std::put_time(localtime_r(&nowTime, &cutTm), "%Y-%m-%d %X");// 2019-06-18 14:25:56

打印程序执行耗时

/*
 * 打印耗时,取变量构造函数与析构函数的时间差,单位ms
 */
class SpendTime
{
public:
    SpendTime():_curTimePoint(std::chrono::steady_clock::now())
    {
    }
    
    ~SpendTime(){
        auto curTime = std::chrono::steady_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(curTime - _curTimePoint);
        cout<<"SpendTime = "<<  duration.count() <<"ms"<<endl;
    }

private:
    std::chrono::steady_clock::time_point _curTimePoint;
};
#include <ctime>
#include <limits>

/*
 * 测量时间流逝
 * 精度依赖于操作系统或编译器,具体依赖于std::clock()的返回值精度及CLOCKS_PER_SEC值的定义
 */
class Timer
{
public:
    Timer() : _startTime(std::clock())
    {
    }

    void Restart()
    {
        _startTime = std::clock();
    }

    /*
     * 构造函数至今的耗时,单位s
     */
    double Elapsed() const
    {
        return double(std::clock() - _startTime) / CLOCKS_PER_SEC;
    }

    /*
     * 最小度量,以秒为单位
     */
    double ElapsedMin() const
    {
        return double(1) / double(CLOCKS_PER_SEC);
    }

    /*
     * 最大度量,以秒为单位
     */
    double ElapsedMax() const
    {
        return (double(std::numeric_limits<std::clock_t>::max()) - double(_startTime) / double(CLOCKS_PER_SEC));
    }


private:
    std::clock_t _startTime;//毫秒级精度
};

判断时间戳是否为当天

#include <iomanip>
#include <thread>
#include <mutex>
#include <iomanip>
#include <chrono>
#include <time.h>

/*
 * 判断是否是当天,时区问题内部已考虑
 * @param    timeStamp        当前时间戳(单位s)
 * @return   0                今天
 *           >0               过去几天
 *           <0               将来几天
 */
int checkTimestamp(const std::time_t timeStamp)
{
    static std::time_t sLastTimestamp = 0;
    if (sLastTimestamp == 0) {
        static std::once_flag oc;
        std::call_once(oc, [&]()
        {
            tzset();//刷新时区
            sLastTimestamp = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
        });
    }
    const int lastDay = (sLastTimestamp - timezone)/86400;//转换到当前时区,自1970年来的天数
    const int curDay = (timeStamp - timezone)/86400;
    sLastTimestamp = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    
    return (curDay - lastDay);
}

<think>我们有一个 `std::vector`,其元素类型为 `std::chrono::time_point<std::chrono::high_resolution_clock>`。我们想使用 `std::max_element` 来查找这个向量中的最大时间点(即最近的时间点)。 ### 问题分析 1. **`std::max_element` 的返回值类型**: - `std::max_element` 是标准算法,用于查找范围中的最大元素。 - 它返回一个迭代器,指向范围中最大元素的位置。 - 因此,返回类型为 `std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>::iterator`。 2. **时间点的比较**: - `std::chrono::time_point` 类型已经重载了比较运算符(如 `<`, `==` 等),因此可以直接使用 `std::max_element` 来比较时间点。 ### 代码示例 ```cpp #include <vector> #include <algorithm> #include <chrono> int main() { // 定义时间点向量 using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>; std::vector<TimePoint> timePoints; // 添加一些时间点(示例) timePoints.push_back(std::chrono::high_resolution_clock::now()); // ... 添加更多时间点 ... // 使用 std::max_element 查找最大时间点 auto maxIt = std::max_element(timePoints.begin(), timePoints.end()); // 此时 maxIt 是指向最大时间点的迭代器 // 如果需要获取该时间点的值,可以解引用 TimePoint maxTime = *maxIt; // 注意:如果向量为空,max_element 将返回 end() 迭代器,因此需要检查 if (maxIt != timePoints.end()) { // 安全地使用 maxTime } return 0; } ``` ### 返回值类型详解 - `std::max_element` 返回的迭代器类型是 `std::vector<TimePoint>::iterator`。 - 如果向量为空,则返回的迭代器等于 `timePoints.end()`。 - 通过解引用迭代器(`*maxIt`)可以得到 `TimePoint` 类型的值,即 `std::chrono::time_point<std::chrono::high_resolution_clock>`。 ### 注意事项 1. **空向量处理**:在使用返回的迭代器前,必须检查它是否有效(即不等于 `end()` 迭代器)。 2. **时间点比较**:时间点按时间先后顺序比较,较早的时间点小于较晚的时间点。因此,`std::max_element` 返回的是最晚的时间点(即最大值)。 3. **性能**:`std::max_element` 的时间复杂度为线性($O(n)$),因为它需要遍历整个向量。 ### 相关问题 1. 如何将 `std::chrono::high_resolution_clock::time_point` 转换为可读的字符串格式? 2. 在比较时间点时,`std::chrono::time_point` 的精度如何保证? 3. 如果时间点向量非常大,如何优化查找最大时间点的性能? 4. 在多线程环境中,如何安全地对时间点向量进行查找最大值操作? 5. 如何同时获取时间点向量中的最小值和最大值(避免两次遍历)? [^1]: `std::chrono::high_resolution_clock` 可能是系统时钟或稳定时钟的别名,具体取决于实现。</think>### `std::max_element` 返回值类型解析 在 `std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>` 上使用 `std::max_element` 时,**返回值类型是迭代器**,具体为: ```cpp std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>::iterator ``` #### 关键特性说明: 1. **迭代器类型** `std::max_element` 返回指向容器中最大元素的迭代器,而非元素本身: ```cpp auto it = std::max_element(vec.begin(), vec.end()); ``` 2. **获取实际值** 需解引用迭代器获得时间点对象: ```cpp using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>; TimePoint maxTime = *it; // 解引用获取时间点 ``` 3. **比较规则** 时间点类型已内置比较运算符,可直接用于 `std::max_element`: ```cpp // 等效于:if (t1 < t2) 按时间先后比较 auto it = std::max_element(vec.begin(), vec.end()); ``` #### 完整使用示例: ```cpp #include <vector> #include <algorithm> #include <chrono> int main() { using Clock = std::chrono::high_resolution_clock; using TimePoint = std::chrono::time_point<Clock>; // 创建时间点向量 std::vector<TimePoint> timePoints; timePoints.push_back(Clock::now() - std::chrono::seconds(5)); timePoints.push_back(Clock::now()); timePoints.push_back(Clock::now() - std::chrono::seconds(10)); // 查找最大时间点(最近时间) auto maxIt = std::max_element(timePoints.begin(), timePoints.end()); // 验证结果 if (maxIt != timePoints.end()) { TimePoint maxTime = *maxIt; auto duration = maxTime.time_since_epoch(); auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration); std::cout << "Max time: " << ms.count() << " ms since epoch\n"; } } ``` #### 注意事项: 1. **空容器处理** 若 vector 为空,返回的迭代器等于 `end()`: ```cpp if (maxIt == vec.end()) { // 处理空容器情况 } ``` 2. **时钟稳定性** 由于 `high_resolution_clock` 可能是 `system_clock` 或 `steady_clock` 的别名[^1],比较不同时间段获取的时间点时需注意: - 如果是 `system_clock`,时间点可能因系统时间调整而回退 - 如果是 `steady_clock`,时间点保证单调递增 3. **性能考虑** 比较操作的时间复杂度为 $O(n)$,对于大型容器可考虑并行算法C++17 起): ```cpp auto policy = std::execution::par; auto it = std::max_element(policy, vec.begin(), vec.end()); ``` ### 相关问题 1. 如何安全地将 `high_resolution_clock::time_point` 转换为日历时间字符串? 2. 当时间点向量为空时,`std::max_element` 的行为是什么? 3. C++17 并行算法时间点比较的性能提升有多少? 4. 如何同时获取时间点向量中的最小值和最大值(避免两次遍历)? 5. 如果 `high_resolution_clock` 是 `steady_clock` 的别名,为什么不能直接转换为日历时间?[^1] [^1]: `high_resolution_clock` 可能是 `system_clock` 或 `steady_clock` 的别名,具体取决于实现[^1][^2]。 [^2]: 时间点比较依赖于时钟特性,`system_clock` 可能受系统时间调整影响[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值