C++时间库chrono_Time_point (三)

chrono_time_point (三)

文章目录
  • chrono_time_point (三)
    • 模板参数
    • 源码解析
    • 构造函数:
    • 成员函数time_since_epoch()
      • 例子
    • timepoint提供的操作
    • timepoint的溢出
    • C和POSIX提供的Date/Time函数
      • 演示案例(timepoint和日历时间的转换)
  • 以计时器停滞线程
      • this_thread::sleep_until,用于将线程休眠直到某个时刻:
      • this_thread::sleep_for,用于将当前线程休眠多长时间:

模板参数

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

std::chrono::time_point 表示一个具体时间,如上个世纪80年代、今天下午3点、火车出发时间等,只要它能用计算机时钟表示。

  • 第一个模板参数Clock用来指定所要使用的时钟(标准库中有三种时钟,system_clock,steady_clock和high_resolution_clock。见4时钟详解),第二个模板函数参数用来表示时间的计量单位(特化的std::chrono::duration<> )
  • 时间点都有一个时间戳,即时间原点。chrono库中采用的是Unix的时间戳1970年1月1日 00:00。所以time_point也就是距离时间戳(epoch)的时间长度(duration)。

源码解析

关键代码摘录如下(格式有调整):

template<class _Clock,	class _Duration = typename _Clock::duration> 
class time_point 
{ 
public: 
    typedef _Clock clock; 
    typedef _Duration duration; 
 
    constexpr time_point()	: _MyDur(_Duration::zero()) {} 
 
    constexpr explicit time_point(const _Duration& _Other)	: _MyDur(_Other) {} 
 
    template<class _Duration2, 
        class = typename enable_if<is_convertible<_Duration2, _Duration>::value,void>::type> 
    constexpr time_point(const time_point<_Clock, _Duration2>& _Tp)  : _MyDur(_Tp.time_since_epoch()) {} 
 
    constexpr _Duration time_since_epoch() const { return (_MyDur); } 
     
private: 
    _Duration _MyDur;	// duration since the epoch 
} 

注明:time_point要求其_Clock模板参数必须满足Clock的要求。

  • time_point的实现很简单,使用Duration类型的成员变量存储时间,make sense!
  • 仔细想想,时间点不就是从0时刻开始经过一定时间间隔的某一个时刻吗?

构造函数:

(1)time_point(); //默认构造函数,时间戳作为其值
(2)template <class Duration2> time_point (const time_point<clock,Duration2>& tp); //拷贝构造函数
(3)explicit time_point (const duration& dtn); //使用duration构造,就是距离时间戳的时间长度

成员函数time_since_epoch()

时间点有个重要的函数:duration time_since_epoch() (用于获取当前时间点距离时间戳的时间长度)

例子

即经常用来得到当前时间点到1970年1月1日00:00的时间距离、该函数返回的duration的精度和构造time_point的时钟(Clock)有关(见4时钟详解)。

#include <iostream>   
#include <chrono>   
#include <ctime>   
using namespace std;  
int main()  
{  
    //距离时间戳2两秒   
    chrono::time_point<chrono::system_clock, chrono::seconds> tp(chrono::seconds(2));  
    cout << "to epoch : " <<tp.time_since_epoch().count() << "s" <<endl;  
    //转化为ctime,打印输出时间点   
    time_t tt = chrono::system_clock::to_time_t(tp);  
    char a[50];  
    ctime_s(a, sizeof(a), &tt);  
    cout << a;  
    system("pause");  
    return 0;  
}  

timepoint提供的操作

  • timepoint提供的操作如下:

img

timepoint的溢出

  • 虽然timepoint的接口用了ratio,这确保了duration单元的溢出会导致编译器报错,但是duration的溢出还是可能会发生
  • 见下面的例子:

img

img

  • 这也说明了chrono是一个duration/timepoint程序库,而不是个date/time程序库。你可以计算duration和timepoint但仍然必须把epoch、最小和最大的timepoint、闰年和闰秒纳入考虑

C和POSIX提供的Date/Time函数

  • **C和POSIX提供的Date/Time函数介绍参阅:**https://blog.youkuaiyun.com/qq_41453285/article/details/102651298
  • *C++标准也提供了C和POSIX所提供的“处理date和time”接口*。原本在<time.h>内的宏、类型、函数,现在被定义在的namespace std内
  • 所提供的操作如下图所示:
    • 宏CLOCK_PER_SEC定义了clock()的单位类型(它返回的是elapsed CPU time,以1/CLOCK_PER_SEC秒计)
    • time_t通常只是“始自UNIX epoch(1970年1月1日)的秒数”。然而根据C和C++标准的说法,也并不保证如此

img

演示案例(timepoint和日历时间的转换)

img

img

img

以计时器停滞线程

  • Duration和timepoint可用于线程或程序(即主线程)的停滞(block)。停滞可以是无条件的,也可以指定最大时间段,或等待一个lock或某条件成立,或等待另一线程结束

  • 提供的操作如下:

    • **sleep_for()和sleep_until():**由this_thead提供用以停滞线程
    • **try_lock_for()和try_lock_until():**用来在等待一个mutex时指定最大时间段
    • wait_for()和wait_until():用来在等待某条件成立或等待一个future时指定最大时间段
  • 所有以…for()结尾的函数都会用到一个duration,所有以…until()结束的函数都会用到一个timepoint

    。例如:

    • this_thread::sleep_for(chrono::seconds(10)); //会停滞当前线程(不无可能是主线程)10秒钟
    • this_thread::sleep_until(chrono::system_clock::now()+chrono::seconds(10)); //停滞当前线程,直到system clock 来到一个“比此刻多10秒”的timepoint
  • 这些调用虽然看起来相同,其实不然:

    • *所有…until()函数,你需要传递一个timepoint,而它收到时间调整的影响*。如果sleep_until()之后的10秒内system clock被调整了,停滞时间也会被相应调整。例如我们把system clock回调1小时,这个程序将被停滞60分钟又10秒。又如果我们把clock调快超过10秒,timer会立刻结束
    • 如果使用…for()函数如sleep_for(),你必须传一个duration,或你使用steady_clock,那么system clock的调整通常不会影响duration。然而在一个不提供steady clock的硬件上,软件平台没机会在不受到“可能被调整的system time”的影响下计算秒数,因此时间的调整也会冲击…for()函数
  • 所有这些timer都不会保证绝对精准。对任何timer而言都存在一点点延迟,因为系统只是周期性地检查那个timer结束了,而timer和interrupt(中断)的处理又需要花费一些时间。因此,timer的时间长度将会是它们所指定的时间加上一小段(取决于实现的质量和当下情势)

this_thread::sleep_until,用于将线程休眠直到某个时刻:

#include <iostream>
#include <chrono>
#include <thread>
 
auto now() { return std::chrono::steady_clock::now(); }
 
auto awake_time() {
    using std::chrono::operator""ms;
    return now() + 2000ms;
}
 
int main()
{
    std::cout << "Hello, waiter...\n" << std::flush;
    const auto start {now()};                        //获取当前时间
    std::this_thread::sleep_until(awake_time());     //当前线程睡眠直到当前时刻的2000ms后
    std::chrono::duration<double, std::milli> elapsed {now() - start};    //线程唤醒,计算时差
    std::cout << "Waited " << elapsed.count() << " ms\n";
    return 0;
}
运行程序输出:

Hello, waiter...
Waited 1999.28 ms
this_thread::sleep_for,用于将当前线程休眠多长时间:
#include <iostream>
#include <chrono>
#include <thread>
 
int main()
{
    using namespace std::chrono_literals;
    std::cout << "Hello waiter\n" << std::flush;
    auto start = std::chrono::high_resolution_clock::now();
    std::this_thread::sleep_for(2000ms);
    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> elapsed = end-start;
    std::cout << "Waited " << elapsed.count() << " ms\n";
    return 0;
}
运行程序输出:

Hello waiter
Waited 2000.07 ms

chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end-start;
std::cout << “Waited " << elapsed.count() << " ms\n”;
return 0;
}


运行程序输出:

Hello waiter
Waited 2000.07 ms

 

C++时间库chrono_Time_point (三)_time_since_epoch-优快云博客

<think>我们有两个任务: 1. 解析 `std::chrono::time_point` 对象,即如何从中提取出具体的时间值(比如年、月、日、时、分、秒等)。 2. 根据用户之前的问题(关于将时间点转换为秒)和引用内容,提供相关解析方法。 注意:`std::chrono::time_point` 本身并不直接存储日历时间(年月日时分秒),而是存储自时钟纪元(epoch)以来的持续时间(duration)。因此,要解析出具体的时间值,我们需要: - 如果使用系统时钟(system_clock),我们可以将其转换为日历时间(因为系统时钟的纪元通常是已知的,如1970年1月1日)。 - 如果使用高分辨率时钟(high_resolution_clock),其纪元是未指定的(可能是系统启动时间),因此通常不用于日历时间,而只用于时间间隔测量。 根据用户之前的问题,他们使用的是 `high_resolution_clock`,但这里要求解析时间值(可能是日历时间)。所以我们需要区分: 情况1:用户想解析为自纪元以来的时间值(如秒数、毫秒数等)——这我们已经知道怎么做(用`time_since_epoch()`然后转换为需要的单位)。 情况2:用户想解析为日历时间(年月日时分秒)——这通常需要系统时钟(system_clock)才能做到。 因此,回答应该包括: A. 如何从 `time_point` 获取自纪元以来的时间值(以秒、毫秒等为单位)。 B. 如何将 `system_clock` 的 `time_point` 转换为日历时间(因为`high_resolution_clock`通常不能直接转为日历时间)。 另外,参考引用内容: [^1]:提到time_point支持floor、ceil和round函数,用于舍入到指定精度。 [^2]:解释了time_point的存储方式(存储自纪元开始的duration)。 [^3]:说明了high_resolution_clock的now()函数返回当前时间点,并提到时钟的稳定性(is_steady)。 所以,我们将分两部分回答: 第一部分:获取自纪元以来的时间值(适用于任何时钟的time_point) 第二部分:转换为日历时间(仅适用于system_clock) 同时,由于用户之前使用的是high_resolution_clock,我们需要提醒:如果目的是获取日历时间,应该使用system_clock。 步骤: 1. 获取自纪元以来的持续时间: ```cpp auto duration_since_epoch = time_point.time_since_epoch(); ``` 2. 将持续时间转换为具体单位(如秒): ```cpp // 转换为秒(整数秒) auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration_since_epoch).count(); // 转换为秒(带小数,双精度浮点) double seconds_d = std::chrono::duration<double>(duration_since_epoch).count(); ``` 3. 转换为日历时间(仅system_clock): C++标准提供了将`system_clock::time_point`转换为`std::time_t`的工具,然后可以用C标准函数(如localtime, gmtime)或C++20的chrono日历工具(如果支持)来转换。 C++20之前: ```cpp #include <chrono> #include <ctime> auto now = std::chrono::system_clock::now(); std::time_t now_time_t = std::chrono::system_clock::to_time_t(now); // 然后使用 std::localtime 或 std::gmtime 转换为tm结构 std::tm* now_tm = std::localtime(&now_time_t); // 注意:localtime不是线程安全的,可以使用localtime_r(POSIX)或C++的std::localtime_s(C11/C++14) ``` C++20及以后(推荐): ```cpp #include <chrono> #include <format> // 或者使用<chrono>中的日历功能 // 使用std::chrono::time_point_cast转换到天精度 auto now = std::chrono::system_clock::now(); auto now_days = std::chrono::floor<std::chrono::days>(now); // 舍入到天 // 然后分解成年月日 auto ymd = std::chrono::year_month_day(now_days); // 获取年、月、日 int year = static_cast<int>(ymd.year()); unsigned month = static_cast<unsigned>(ymd.month()); unsigned day = static_cast<unsigned>(ymd.day()); // 对于时间部分(时分秒) auto time_of_day = std::chrono::hh_mm_ss(now - now_days); // 计算从当天开始的时间 auto hours = time_of_day.hours().count(); auto minutes = time_of_day.minutes().count(); auto seconds = time_of_day.seconds().count(); ``` 4. 对于非system_clock(如high_resolution_clock),通常无法直接转换为日历时间,因为纪元未知。如果一定要转换,需要知道该时钟的纪元与系统时钟的关系(例如,通过记录两个时钟的当前时间差来转换),但这不可移植。 因此,在回答中,我们将强调: - 如果目的是测量时间间隔,使用high_resolution_clock并转换为秒/毫秒等。 - 如果目的是获取日历时间,使用system_clock。 同时,我们可以提供一些示例代码。 由于用户要求解析时间值,我们提供两种场景的代码。 注意:用户上次的问题是关于将high_resolution_clock的时间点转换为秒,所以这次的问题可能是想进一步分解时间值(比如得到小时、分钟等),但需要明确时钟类型。 我们假设用户可能有两种意图,因此分别说明。 回答结构: 1. 直接解析时间点为数值(秒、毫秒等) - 适用于任何时钟 2. 解析为日历时间(年月日时分秒) - 仅适用于system_clock 最后,生成相关问题。</think>### 解析 `std::chrono::time_point` 的时间值 `std::chrono::time_point` 表示特定时钟上的一个时间点,其内部存储自时钟纪元(epoch)开始的持续时间值。解析其时间值需要以下步骤: --- #### 1. **获取自纪元起的持续时间** 通过 `time_since_epoch()` 获取自时钟纪元起的 `duration` 对象: ```cpp auto tp = std::chrono::high_resolution_clock::now(); // 获取时间点 auto duration = tp.time_since_epoch(); // 获取自纪元起的持续时间 ``` #### 2. **转换为具体时间单位** 将 `duration` 转换为所需时间单位(如秒、毫秒等): ```cpp // 转换为整数秒 auto sec_int = std::chrono::duration_cast<std::chrono::seconds>(duration).count(); // 转换为浮点秒(保留小数) double sec_float = std::chrono::duration<double>(duration).count(); // 转换为毫秒 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); // 转换为微秒 auto us = std::chrono::duration_cast<std::chrono::microseconds>(duration).count(); ``` #### 3. **转换为日历时间(仅适用于 `system_clock`)** 若需人类可读时间(年月日时分秒),需使用 `system_clock`: ```cpp #include <ctime> auto sys_tp = std::chrono::system_clock::now(); // 系统时钟时间点 // 转换为 time_t 结构 std::time_t t = std::chrono::system_clock::to_time_t(sys_tp); // 转换为本地时间字符串 std::cout << "Local time: " << std::ctime(&t); // 分解为 tm 结构(线程不安全) std::tm* tm_ptr = std::localtime(&t); int year = tm_ptr->tm_year + 1900; // 年份 int month = tm_ptr->tm_mon + 1; // 月份 ``` --- ### 关键说明 1. **时钟类型差异**: - `high_resolution_clock`:适合高精度计时,但纪元未标准化,**不能直接转日历时间**[^3]。 - `system_clock`:纪元固定(通常为 1970-01-01),可直接转日历时间[^1][^2]。 2. **精度控制**: - 使用 `duration_cast` 控制舍入方式: ```cpp auto sec_floor = std::chrono::floor<std::chrono::seconds>(duration); // 向下取整 auto sec_ceil = std::chrono::ceil<std::chrono::seconds>(duration); // 向上取整 ``` 3. **C++20 增强**(推荐): ```cpp // 直接分解为日历组件 auto ymd = std::chrono::year_month_day(std::chrono::floor<std::chrono::days>(sys_tp)); int year = static_cast<int>(ymd.year()); unsigned month = static_cast<unsigned>(ymd.month()); ``` [^1][^2] --- ### 示例代码 ```cpp #include <iostream> #include <chrono> #include <ctime> int main() { // 解析高精度时钟(数值形式) auto hp_tp = std::chrono::high_resolution_clock::now(); auto us = std::chrono::duration_cast<std::chrono::microseconds>( hp_tp.time_since_epoch() ).count(); std::cout << "自纪元起的微秒数: " << us << "\n"; // 解析系统时钟(日历时间) auto sys_tp = std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(sys_tp); std::cout << "日历时间: " << std::ctime(&t); return 0; } ``` > **注意**:`high_resolution_clock` 的纪元由实现定义(可能是系统启动时间),通常仅用于时间间隔测量[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值