【C++】chono库:使用及源码分析

news2025/1/19 11:28:31

文章目录

  • 0. 概述
  • 1. duration
    • 1.1 分析
      • std::chrono::duration_cast()
    • 1.2 使用案例
      • std::chrono::duration::count()
    • 1.3 部分源码
  • 2. time_point
    • 2.1 分析
      • std::chrono::time_point_cast()
    • 2.2 使用举例
      • std::chrono::time_point::time_since_epoch()
    • 2.3 部分源码

0. 概述

本篇文章介绍 chrono 模板库,是参考 cplusplus.com 官网做的一篇详解。
chrono 库是可以实现各种时间格式的定义和转化,整体分成三部分。

  1. duration 类
    用作 测量时间跨度,比如:1分钟,2小时,或者10毫秒。
    使用 duration 类模板的对象来表示时,可以将计数表示和周期精度耦合在一起(例如:10表示计数,毫秒表示周期精度)
  2. time_point 类
    用作 表示某一个时间点,比如:日出的时间,某人的纪念日
    使用 time_point 类模板的对象来表示时,需要指定 clock(三种,后面有讲) 和相对于纪元的持续时间来表示这一点
namespace chrono 
{
	// duration 类
	template <class _Rep, class _Period> class duration;
	// time_point 类
	template <class _Clock, class _Duration = typename _Clock::duration> class time_point;
	// ...
}
  1. clock 结构体
    就像名称所示,时钟,可以将时间点与实际物理时间联系起来。
    主要介绍三个时钟,它们提供了将当前时间表示为时间点的方法
    1. 系统时钟 system_clock
    2. 稳定时钟 steady_clock
    3. 高精度时钟 high_resolution_clock
namespace chrono 
{
    struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime
        using rep                       = long long;
        using period                    = ratio<1, 10'000'000>; // 100 nanoseconds
        using duration                  = _CHRONO duration<rep, period>;
        using time_point                = _CHRONO time_point<system_clock>;
        static constexpr bool is_steady = false;
	// 获取当前时间
        static time_point now();
	// time_point 类型转化成 time_t
        static __time64_t to_time_t(const time_point& _Time);
	// time_t 类型转化成 time_point
        static time_point from_time_t(__time64_t _Tm);
    };


    struct steady_clock { // wraps QueryPerformanceCounter
        using rep                       = long long;
        using period                    = nano;
        using duration                  = nanoseconds;
        using time_point                = _CHRONO time_point<steady_clock>;
        static constexpr bool is_steady = true;

        static time_point now() noexcept { // get current time
            const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot
            const long long _Ctr  = _Query_perf_counter();
            static_assert(period::num == 1, "This assumes period::num == 1.");
            // 10 MHz is a very common QPC frequency on modern PCs. Optimizing for
            // this specific frequency can double the performance of this function by
            // avoiding the expensive frequency conversion path.
            constexpr long long _TenMHz = 10'000'000;
            if (_Freq == _TenMHz) {
                static_assert(period::den % _TenMHz == 0, "It should never fail.");
                constexpr long long _Multiplier = period::den / _TenMHz;
                return time_point(duration(_Ctr * _Multiplier));
            } else {
                // Instead of just having "(_Ctr * period::den) / _Freq",
                // the algorithm below prevents overflow when _Ctr is sufficiently large.
                // It assumes that _Freq * period::den does not overflow, which is currently true for nano period.
                // It is not realistic for _Ctr to accumulate to large values from zero with this assumption,
                // but the initial value of _Ctr could be large.
                const long long _Whole = (_Ctr / _Freq) * period::den;
                const long long _Part  = (_Ctr % _Freq) * period::den / _Freq;
                return time_point(duration(_Whole + _Part));
            }
        }
    };
   
    _EXPORT_STD using high_resolution_clock = steady_clock;
} // namespace chrono

1. duration

1.1 分析

template <class _Rep, class _Period> class duration;
  • _Rep 表示一种数值类型,用来表示 _Period 的类型,比如:int, float, double…
  • _Periodratio 类型,表示 用秒表示的时间单位 比如:second, milisecond…

常用的duration<Rep,Period>已经定义好了,在 std::chrono下:

// std::chrono
using nanoseconds	= duration<long long, nano>;
using microseconds	= duration<long long, micro>;
using milliseconds	= duration<long long, milli>;
using seconds		= duration<long long>;
using minutes		= duration<int, ratio<60>>;
using hours			= duration<int, ratio<3600>>;
using days			= duration<int, ratio_multiply<ratio<24>, hours::period>>;
using weeks			= duration<int, ratio_multiply<ratio<7>, days::period>>;
using years			= duration<int, ratio_multiply<ratio<146097, 400>, days::period>>;
using months		= duration<int, ratio_divide<years::period, ratio<12>>>;

std::chrono::duration_cast()

由于 duration 的种类繁多,chrono 库提供了duration_cast 类型转换函数模板,在模板参数中填写需要转成的类型如:<std::chrono::seconds / months / days…>,就可以得到想要的结果,std::chrono 下:

// std::chrono
template <class _To, class _Rep, class _Period, enable_if_t<_Is_duration_v<_To>, int> /* = 0 */>
    _To duration_cast(const duration<_Rep, _Period>& _Dur)

1.2 使用案例

🌰典型的用法是表示一段时间:

// duration constructor
#include <iostream>
#include <chrono>
	
int main ()
{
	typedef std::chrono::duration<int> seconds_type;
	typedef std::chrono::duration<int,std::milli> milliseconds_type;
	typedef std::chrono::duration<int,std::ratio<60*60>> hours_type;
	
	hours_type h_oneday (24);                  // 24h
	seconds_type s_oneday (60*60*24);          // 86400s
	milliseconds_type ms_oneday (s_oneday);    // 86400000ms
	
	seconds_type s_onehour (60*60);            // 3600s
	//hours_type h_onehour (s_onehour);          // NOT VALID (type truncates), use:
	hours_type h_onehour (std::chrono::duration_cast<hours_type>(s_onehour));
	milliseconds_type ms_onehour (s_onehour);  // 3600000ms (ok, no type truncation)
	
	std::cout << ms_onehour.count() << "ms in 1h" << std::endl;
	
	return 0;
}
--------------------------
输出结果:
3600000ms in 1h
  • 需要注意的就是,大单位的 duration 可以作为参数构造小单位,反过来就不行了,需要使用 duration_cast 进行强转。
    在这里插入图片描述

std::chrono::duration::count()

🌰 duration 还有一个成员函数 count() 返回 Rep 类型的 Period 数量:

// duration::count
#include <iostream>     
#include <chrono>       // std::chrono::seconds, std::chrono::milliseconds,std::chrono::duration_cast
using namespace std::chrono;

int main ()
{
	milliseconds foo (1000); // 1 second,这里的 milliseconds 是库里的,定义见 1.1
	foo*=60;
	
	std::cout << "duration (in periods): ";
	std::cout << foo.count() << " milliseconds.\n";
	
	std::cout << "duration (in seconds): ";
	std::cout << foo.count() * milliseconds::period::num / milliseconds::period::den;
	std::cout << " seconds.\n";
	
	return 0;
}
-------------------------------
输出结果:
duration (in periods): 60000 milliseconds.
duration (in seconds): 60 seconds.

1.3 部分源码

template <class _Rep, class _Period>
class duration { // represents a time duration
public:
    using rep    = _Rep;
    using period = typename _Period::type;

    template <class _Rep2, enable_if_t<is_convertible_v<const _Rep2&, _Rep> && (treat_as_floating_point_v<_Rep> !treat_as_floating_point_v<_Rep2>), int> = 0>
    duration(const _Rep2& _Val) : _MyRep(static_cast<_Rep>(_Val)) {}
    
    template <class _Rep2, class _Period2, enable_if_t<treat_as_floating_point_v<_Rep> || (_Ratio_divide_sfinae<_Period2, _Period>::den == 1 && !treat_as_floating_point_v<_Rep2>), int> = 0>
    duration(const duration<_Rep2, _Period2>& _Dur) : _MyRep(_CHRONO duration_cast<duration>(_Dur).count()) {}

    _Rep count() const 
    {
        return _MyRep;
    }

    common_type_t<duration> operator+() const;
    common_type_t<duration> operator-() const;
    duration& operator++();
    duration operator++(int);
    // -- (略)
    duration& operator+=(const duration& _Right);
    duration& operator-=(const duration& _Right);
    // *= /= %= (略)

// 返回为 0 的 duration 类型
    static duration zero();
// 返回相应 _Rep 类型的最小值 的 duration
    static duration(min)();
// 返回相应 _Rep 类型的最大值 的 duration
    static duration(max)();

private:
    _Rep _MyRep; // the stored rep
};

2. time_point

2.1 分析

template <class _Clock, class _Duration = typename _Clock::duration> class time_point;

类型 std::chrono::time_point 表示一个具体时间,鉴于我们使用时间的情景不同,这个 time point 具体到什么程度,由选用的单位决定。模板参数如下:

  • 时钟类型(见 clock 部分)
  • duration 的时间类型,决定了 time_point 的时间类型

std::chrono::time_point_cast()

由于各种 time_point 表示方式不同,chrono 也提供了相应的转换函数 time_point_cast()。

template <class _To, class _Clock, class _Duration, enable_if_t<_Is_duration_v<_To>, int> = 0>
time_point<_Clock, _To> time_point_cast(const time_point<_Clock, _Duration>& _Time);
{
	// change the duration type of a time_point; truncate
	return time_point<_Clock, _To>(_CHRONO duration_cast<_To>(_Time.time_since_epoch()));
}

2.2 使用举例

以 system_clock 这个时钟举例,里面涉及的起始时间,是计算机元年 1970年1月1日8点(后文简称计元)。

🌰代码如下:

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

int main ()
{
	// 用时钟 system_clock::time_point 直接声明,其值默认为:纪元时间
	system_clock::time_point tp_epoch;
	std::time_t tt = system_clock::to_time_t(tp_epoch);		// 转成 time_t 后可查

	// 用 time_point 类(tp_seconds 的时间周期是 second)
	time_point<system_clock, duration<int>> tp_seconds(duration<int>(1));	// duration 不传时间精度,就默认是 second
	std::cout << tp_seconds.time_since_epoch().count() << std::endl;

	// 用时钟 system_clock::time_point (time_point) 构造对象,时间周期默认是 1/10000000 s
	system_clock::time_point tp(tp_seconds);
	std::cout << "1 second since system_clock epoch = ";
	std::cout << tp.time_since_epoch().count();
	std::cout << " system_clock periods." << std::endl;

	// 打印
	std::cout << "time_point tp_epoch is: " << ctime(&tt);
	tt = system_clock::to_time_t(tp);
	std::cout << "time_point tp is:       " << ctime(&tt);

	return 0;
}
------------------------------
输出结果:
1
1 second since system_clock epoch = 10000000 system_clock periods.
time_point tp_epoch is : Thu Jan  1 08 : 00 : 00 1970
time_point tp is : Thu Jan  1 08 : 00 : 01 1970

std::chrono::time_point::time_since_epoch()

time_point 有一个函数 time_since_epoch() 用来获得1970年1月1日到 time_point 时间经过的duration。同样,如果 time_point 以天为单位,函数返回的 duration 就以天为单位。

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

int main()
{
	typedef duration<int, std::ratio<60 * 60 * 24>> days_type;	// ratio以second为单位,这里的duration时间跨度为1day
	time_point<system_clock, days_type> today = time_point_cast<days_type>(system_clock::now());
	std::cout << today.time_since_epoch().count() << " days since epoch" << std::endl;

	return 0;
}
--------------------
输出结果:
19679 days since epoch

2.3 部分源码

template <class _Clock, class _Duration = typename _Clock::duration>
    class time_point { // represents a point in time
    public:
        using clock    = _Clock;
        using duration = _Duration;
        using rep      = typename _Duration::rep;
        using period   = typename _Duration::period;

        time_point(const _Duration& _Other): _MyDur(_Other) {}

        template <class _Duration2, enable_if_t<is_convertible_v<_Duration2, _Duration>, int> = 0>
        constexpr time_point(const time_point<_Clock, _Duration2>& _Tp): _MyDur(_Tp.time_since_epoch()) {}

        _Duration time_since_epoch() const
        {
            return _MyDur;
        }

        time_point& operator++() noexcept(is_arithmetic_v<rep>);
        time_point operator++(int) noexcept(is_arithmetic_v<rep>);
        time_point& operator--() noexcept(is_arithmetic_v<rep>);
        time_point operator--(int) noexcept(is_arithmetic_v<rep>);
        time_point& operator+=(const _Duration& _Dur);
        time_point& operator-=(const _Duration& _Dur);
        static time_point(min)();
        static time_point(max)();

    private:
        _Duration _MyDur{duration::zero()}; // duration since the epoch
    };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1224691.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】栈与队列面试题(C语言)

我们再用C语言做题时&#xff0c;是比较不方便的&#xff0c;因此我们在用到数据结构中的某些时只能手搓或者Ctrlcv 我们这里用到的栈或队列来自栈与队列的实现 有效的括号 有效的括号&#xff0c;链接奉上。 解题思路&#xff1a; 先说结论&#xff1a; 因为我们是在讲栈与…

mac系统安装docker desktop

Docker的基本概念 Docker 包括三个基本概念: 镜像&#xff08;Image&#xff09;&#xff1a;相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。比如说nginx,mysql,redis等软件可以做成一个镜像。容器&#…

C++知识点总结(6):高精度乘法

一、高精度数 低精度数 1. 输入两个数字 char a_str[1005] {}; long long b; cin >> a_str >> b; 2. 将高精度数转换为整型 int a[1005] {}; int len_a strlen(a_str); for (int i 0; i < len_a-1; i) {a[len_a-i-1] a_str[i] - 48; } 3. 计算 int …

java Could not resolve placeholder

1、参考&#xff1a;https://blog.csdn.net/yu1812531/article/details/123466616 2、配置文件: 3、在application.properties中设置要使用的配置文件

APIcloud 【现已更名 用友开发中心】 iOS发版 应用程序请求用户同意访问相机和照片,但没有在目的字符串中充分说明相机和照片的使用。

iOS 审核时 提示 首次安装软件 获取相机 相册 提示信息 怎么修改 我们注意到你的应用程序请求用户同意访问相机和照片&#xff0c;但没有在目的字符串中充分说明相机和照片的使用。 为了解决这个问题&#xff0c;修改应用信息中的目的字符串是合适的。相机和照片的Plist文件&a…

【giszz笔记】产品设计标准流程【6】

目录 六、组织评审 1.评审的类型 2.评审的人员——谁参加评审 3.评审的核心——怎么提问 & 答案谁说了算 4.评审的流程——前中后三部曲 5.评审的标的——漂亮的靶子 6.避免被“烤”问的一些技巧 7.搞几次评审比较好 这个产品设计系列&#xff0c;陆陆续续写了6篇了…

【DevOps】Git 图文详解(三):常用的 Git GUI

Git 图文详解&#xff08;三&#xff09;&#xff1a;常用的 Git GUI 1.SourceTree2.TortoiseGit3.VSCode 中的 Git 如果不想用命令行工具&#xff0c;完全可以安装一个 Git 的 GUI 工具&#xff0c;用的更简单、更舒服。不用记那么多命令了&#xff0c;极易上手&#xff0c;不…

C++初阶 日期类的实现(下)

目录 一、输入输出(>>,<<)重载的实现 1.1初始版 1.2友元并修改 1.2.1简单介绍下友元 1.2.2修改 1.3>>重载 二、条件判断操作符的实现 2.1操作符的实现 2.2!操作符的实现 2.3>操作符的实现 2.4>,<,<操作符的实现 三、日期-日期的实现 …

深入理解网络协议:通信世界的基石

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在当今数字化时代&#xff0c;网络协议是连接世…

Intellij Idea屏蔽日志/过滤日志

一、安装插件 Grep Console 二、设置关键词&#xff0c;过滤日志 关键词的前后加上 .* 符号&#xff0c;类似&#xff1a; .*关键词.*设置后 &#xff0c;点击 Apply 即可过滤日志。

上网行为审计软件能审计到什么

上网行为审计软件是一种用于监控和分析员工在工作时间使用互联网行为的软件工具。这种软件可以帮助企业管理员工在工作时间内的互联网使用情况&#xff0c;以确保员工的行为符合企业规定和法律法规。 域之盾软件---上网行为审计软件可以审计到以下内容&#xff1a; 1、网络访问…

FFmpeg 6.1 发布,7.0时代即将来临

11月10日&#xff0c;FFmpeg 6.1正式发布。 FFmpeg 发布版本的时候&#xff0c;按照惯例&#xff0c;会选择一些物理学家名字作为代号&#xff0c;这一新版本代号为“Heaviside”。主要为纪念伟大的英国数学家和物理学家奥利弗黑维塞&#xff08;Oliver Heaviside)。 奥利弗黑维…

Vulhub靶场-KIOPTRIX: LEVEL 1

目录 环境配置 端口扫描 漏洞发现 mod_ssl漏洞利用 Samba远程代码执行漏洞利用 环境配置 首先去官网下载靶场导入到虚拟机中 下载地址&#xff1a;Kioptrix: Level 1 (#1) ~ VulnHub 下载完成之后导入到vmware中 这里需要改nat&#xff0c;桥接模式的靶机拿不到IP&…

Windows10下Tomcat8.5安装教程

文章目录 1.首先查看是否安装JDK。2.下载3.解压到指定目录&#xff08;安装路径&#xff09;4.启动Tomcat5.常见问题5.1.如果出现报错或者一闪而过5.2.Tomcat乱码 1.首先查看是否安装JDK。 CMD窗口输入命令 java -version 2.下载 历史版本下载地址&#xff1a;https://archi…

tomcat8.5处理get请求时,控制台输出中文乱码问题的解决

问题描述 控制台输出中文乱码 版本信息 我使用的是tomcat8.5 问题解决 配置web.xml 注&#xff1a;SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前&#xff0c;否则无效 <!--配置springMVC的编码过滤器--> <filter><filter-name>CharacterEn…

Qt6版使用Qt5中的类遇到的问题解决方案

如果有需要请关注下面微信公众号&#xff0c;会有更多收获&#xff01; 1.QLinkedList 是 Qt 中的一个双向链表类。它提供了高效的插入和删除操作&#xff0c;尤其是在中间插入和删除元素时&#xff0c;比 QVector 更加优秀。下面是使用 QLinkedList 的一些基本方法&#xff1a…

量化交易:公司基本面的量化

公司的基本面因素一直具备滞后性&#xff0c;令基本面的量化出现巨大困难。而从上市公司的基本面因素来看&#xff0c;一般只有每个季度的公布期才会有财务指标的更新&#xff0c;而这种财务指标的滞后性对股票表现是否有影响呢&#xff1f;如何去规避基本面滞后产生的风险呢&a…

openGauss学习笔记-126 openGauss 数据库管理-设置账本数据库-归档账本数据库

文章目录 openGauss学习笔记-126 openGauss 数据库管理-设置账本数据库-归档账本数据库126.1 前提条件126.2 背景信息126.3 操作步骤 openGauss学习笔记-126 openGauss 数据库管理-设置账本数据库-归档账本数据库 126.1 前提条件 系统中需要有审计管理员或者具有审计管理员权…

图像分类(一) 全面解读复现AlexNet

解读 论文原文&#xff1a;http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf Abstract-摘要 翻译 我们训练了一个庞大的深层卷积神经网络&#xff0c;将ImageNet LSVRC-2010比赛中的120万张高分辨率图像分为1000个不…

【Python自动化】定时自动采集,并发送微信告警通知,全流程案例讲解!

文章目录 一、概要二、效果演示三、代码讲解3.1 爬虫采集行政处罚数据3.2 存MySQL数据库3.3 发送告警邮件&微信通知3.4 定时机制 四、总结 一、概要 您好&#xff01;我是马哥python说&#xff0c;一名10年程序猿。 我原创开发了一套定时自动化爬取方案&#xff0c;完整开…