C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)(一)https://developer.aliyun.com/article/1465308
5. 使用std::chrono作为通用的时间参数
5.1 std::chrono::duration的应用
在我们的日常生活中,时间是一个我们经常要处理的量。我们处理从秒到分钟,到小时,甚至到年。这就像我们的基本需求层次。根据马斯洛的需求层次理论(Maslow’s hierarchy of needs),我们首先满足生理需求,然后是安全需求,然后是爱和归属感,然后是尊重,最后是自我实现。同样地,我们在处理时间时,也需要从满足基本的时间单位开始,比如秒,然后我们可能需要更大的单位,比如分钟或小时,然后我们可能需要处理更复杂的时间单位,比如日、周、月、年。C++的std::chrono::duration
就是设计来帮助我们处理这种层次化需求的。
std::chrono::duration
(时长)是一个模板类,用于表示两个时间点之间的时间跨度。其模板参数是表示此时间跨度的单位。
5.1.1 创建duration对象
我们可以通过以下方式创建duration对象:
std::chrono::duration<int> twenty_seconds(20); std::chrono::duration<double, std::ratio<60>> half_a_minute(0.5); std::chrono::duration<long, std::ratio<1,1000>> one_millisecond(1);
在上面的例子中,twenty_seconds
是20秒,half_a_minute
是半分钟,one_millisecond
是1毫秒。
5.1.2 duration对象的操作
我们可以对duration
对象进行各种操作,包括比较、算术运算、赋值等。这就像我们在处理日常生活中的时间需求一样。比如,我们可以比较今天和昨天哪天更长,或者我们可以计算如果我们每天工作8小时,一周工作多少小时。在C++中,我们可以这样做:
std::chrono::seconds work_day(8*60*60); // 8 hours std::chrono::seconds work_week = 5*work_day;
下面是一个表格,总结了std::chrono::duration
的一些常见操作:
操作 | 描述 |
duration1 + duration2 |
两个duration对象相加,返回一个新的duration对象 |
duration1 - duration2 |
两个duration对象相减,返回一个新的duration对象 |
duration1 * n 或 n * duration1 |
duration对象与一个数相乘,返回一个新的duration对象 |
duration1 / n |
duration对象除以一个 |
数,返回一个新的duration对象 |
| duration1 == duration2
| 检查两个duration对象是否相等 |
| duration1 != duration2
| 检查两个duration对象是否不相等 |
| duration1 < duration2
| 检查一个duration对象是否小于另一个 |
| duration1 > duration2
| 检查一个duration对象是否大于另一个 |
| duration1 <= duration2
| 检查一个duration对象是否小于或等于另一个 |
| duration1 >= duration2
| 检查一个duration对象是否大于或等于另一个 |
请注意,所有这些操作都不会改变原始的duration
对象,而是返回一个新的duration
对象。
以此为核心,std::chrono::duration
可以被看作是一个“构建块”,使我们可以创建、操作和比较不同的时间单位。在我们开始处理更复杂的时间需求时,它为我们提供了一个基础。同样,它也可以被用作一个通用的时间参数,在我们的函数或类中。
5.2 时间单位转换:如std::chrono::seconds, std::chrono::milliseconds, std::chrono::microseconds等
在处理时间相关问题时,一个常见的需求就是在不同的时间单位之间进行转换。举一个生活中的例子,我们可能想要知道1000毫秒(milliseconds)是多少秒(seconds)。同样的,在编程中,我们也可能需要做这样的转换。在C++的std::chrono
库中,提供了一种非常方便的方式来进行这种转换。
5.2.1 时间单位的转换
假设我们有一个std::chrono::milliseconds
对象,我们想要将它转换为std::chrono::seconds
,我们可以使用std::chrono::duration_cast
函数,如下所示:
std::chrono::milliseconds ms(1000); std::chrono::seconds sec = std::chrono::duration_cast<std::chrono::seconds>(ms);
这里,duration_cast
函数会将ms
对象转换为sec
对象。值得注意的是,这个转换是向下取整的。也就是说,如果ms
是1500毫秒,那么sec
将是1秒。
我们可以将这个过程想象为将一堆石头(milliseconds)转移到不同大小的箱子(seconds)。我们不能将半块石头放进箱子里,所以我们必须将多余的石头扔掉。这就是duration_cast
函数向下取整的原因。
5.2.2 std::chrono中的时间单位
std::chrono
库中定义了许多常用的时间单位,比如:
std::chrono::hours
std::chrono::minutes
std::chrono::seconds
std::chrono::milliseconds
std::chrono::microseconds
std::chrono::nanoseconds
这些单位都是std::chrono::duration
的特化版本。它们的使用方法与std::chrono::duration
完全相同,只是它们的模板参数已经被预设为常用的值。
此外,你也可以使用std::ratio
创建自定义的时间单位,比如:
using half_seconds = std::chrono::duration<double, std::ratio<1, 2>>;
在上面的代码中,half_seconds
代表半秒。
通过使用std::chrono
库中的时间单位,我们可以更方便地处理时间相关的问题,就像我们在生活中使用小时、分钟和秒一样。
6. 深入探讨std::chrono::system_clock::time_point
6.1. time_point的定义和主要特性
std::chrono::system_clock::time_point
(时间点)可以被视为一个特殊的"时间戳",它表示自纪元以来的时间量。纪元是指定的起点时间,对于std::chrono::system_clock
来说,纪元通常是1970年1月1日午夜。
在这个定义中,我们可以看出time_point
的核心概念:它是一个表示时间的数值,而不是一个具体的“现在”,“过去”或“将来”。正如著名心理学家阿布拉罕·马斯洛(Abraham Maslow)在描述人类需求层次时指出,满足低层需求是实现高层需求的基础。类似地,理解time_point
的定义和性质是我们理解更高级和更复杂的时间处理技术的基础。
std::chrono::system_clock::time_point
是一个模板类型,可以表示不同精度的时间。例如,我们可以用std::chrono::system_clock::time_point
表示到纳秒级别的精确时间。
下表总结了一些time_point
的主要方法:
方法名称 | 描述 | 返回类型 |
min() | 获取可能的最小时间点 | system_clock::time_point |
max() | 获取可能的最大时间点 | system_clock::time_point |
now() | 获取从纪元开始到现在的时间点 | system_clock::time_point |
为了更好地理解time_point
,我们可以将其比喻为一个足球场上的地标。纪元(epoch)就像球场的一端,而time_point
就像球场上的一个具体位置,通过度量从球场一端到这个位置的距离(时间),我们可以确定这个位置的确切位置。
time_point的使用示例
#include <iostream> #include <chrono> int main() { // 获取当前的时间点 std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); // 转换为时间戳并打印 std::time_t now_c = std::chrono::system_clock::to_time_t(now); std::cout << "Current time: " << std::ctime(&now_c) << std::endl; return 0; }
在上述示例中,我们获取了当前的时间点,并将其转换为C时间,然后打印。这只是time_point
的基本使用,随着我们深入研究std::chrono
库,我们将发现更多关于time_point
的有趣和强大的应用。
6.2. time_point的常见操作与示例
在了解了std::chrono::system_clock::time_point
的定义和基本特性之后,我们可以探索一些对time_point
进行操作的方法。这些操作包括了加减运算、比较、以及转换为其他时间单位等。
这些操作提供了我们对时间进行更深层次的控制,类似于心理学中的"自我效能"理论,人们对自己能否成功完成任务的信心,可以决定他们是否会尝试这个任务,以及他们在面对困难时是否会坚持。对time_point
的操作提供了这样的“自我效能”,使我们在面对复杂的时间问题时,能有信心进行处理。
加减运算
我们可以对time_point
进行加减运算来得到新的time_point
:
#include <iostream> #include <chrono> int main() { // 获取当前时间点 std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); // 创建一个1小时的duration对象 std::chrono::hours one_hour(1); // 通过加法运算得到1小时后的时间点 std::chrono::system_clock::time_point one_hour_later = now + one_hour; return 0; }
在上述代码中,我们首先获取了当前的时间点now
,然后创建了一个表示1小时的std::chrono::hours
对象one_hour
。通过将now
和one_hour
进行加法运算,我们得到了1小时后的时间点one_hour_later
。
比较操作
我们可以使用比较操作符比较两个time_point
对象:
#include <iostream> #include <chrono> int main() { // 获取当前时间点 std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); // 创建一个1秒后的时间点 std::chrono::system_clock::time_point one_sec_later = now + std::chrono::seconds(1); // 比较两个时间点 if (one_sec_later > now) { std::cout << "one_sec_later is later than now.\n"; } else { std::cout << "one_sec_later is not later than now.\n"; } return 0; }
在上述代码中,我们创建了一个1秒后的时间点one_sec_later
,然后使用大于操作符>
比较了one_sec_later
和now
,并打印了比较结果。
通过上述示例,我们可以看到,std::chrono::system_clock::time_point
提供了一种直观、灵活的方式来操作和比较时间。这就像我们通过心理学的理论和技术来理解和控制自己的行为和情绪一样,通过理解和掌握time_point
,我们可以更好地控制和操作时间。
6.3. time_point在实际问题中的应用示例
std::chrono::system_clock::time_point
在实际问题中的应用往往涉及到复杂的时间处理,例如事件的调度,网络通信的超时控制等。在这些问题中,我们需要对time_point
进行精细的操作和处理。
事件调度
在许多情况下,我们需要在某个具体的时间点执行某个任务或事件。这就需要我们能够准确地表示和计算时间点。以下是一个简单的示例:
#include <iostream> #include <chrono> #include <thread> void schedule_event(std::chrono::system_clock::time_point event_time) { std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); if (event_time > now) { // 计算需要等待的时间 std::chrono::duration<double> wait_time = event_time - now; // 等待相应的时间 std::this_thread::sleep_for(wait_time); } // 执行事件 std::cout << "Event executed at " << std::chrono::system_clock::to_time_t(now) << std::endl; } int main() { // 计划在5秒后执行事件 std::chrono::system_clock::time_point event_time = std::chrono::system_clock::now() + std::chrono::seconds(5); schedule_event(event_time); return 0; }
在上述代码中,我们首先计算了事件的执行时间event_time
,然后调用schedule_event
函数来执行事件。在schedule_event
函数中,我们先获取当前的时间,然后计算出需要等待的时间,并使用std::this_thread::sleep_for
函数来等待相应的时间,最后执行事件。
就像心理学家给出的建议,我们在面对复杂任务时,需要将其分解成小的、可管理的部分。这样,我们可以更好地控制任务的执行,并实现我们的目标。在这个示例中,我们首先计算了事件的执行时间,然后等待相应的时间,最后执行事件。这就是一个典型的任务分解的例子。
网络通信的超时控制
在网络通信中,超时控制是非常重要的一部分。例如,在建立连接、发送数据时,如果在一定时间内没有得到回应,我们需要进行超时处理。这就需要我们能够精确地表示和计算时间。以下是一个简单的示例:
#include <iostream> #include <chrono> #include <thread> bool try_connect(std::chrono::system_clock::time_point deadline) { while (std::chrono::system_clock::now() < deadline) { // 尝试连接 bool success = false; // 这里只是示例,实际应用 中需要调用具体的连接函数 if (success) { return true; } // 等待一段时间后再尝试 std::this_thread::sleep_for(std::chrono::seconds(1)); } // 超时,连接失败 return false; } int main() { // 尝试在10秒内建立连接 std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + std::chrono::seconds(10); bool connected = try_connect(deadline); if (connected) { std::cout << "Connected.\n"; } else { std::cout << "Failed to connect within 10 seconds.\n"; } return 0; }
在上述代码中,我们设置了一个超时时间deadline
,然后在这个时间内不断尝试建立连接。如果在超时时间内成功建立了连接,则返回true
;否则,返回false
。这就像我们在面对困难时,需要有持久性和决心。如果我们坚持尝试,而不是在失败后立即放弃,我们往往可以实现我们的目标。
通过上述示例,我们可以看到,std::chrono::system_clock::time_point
提供了一种强大、灵活的方式来表示和操作时间,使我们可以有效地解决实际问题。
7. 深入探讨std::chrono::duration
7.1 duration的定义和主要特性
std::chrono::duration
(时长)是C++中表示时间段的类型。它是一个模板类,可以表示秒、毫秒、微秒等不同的时间单位。
为了更好地理解duration
,让我们从心理学的角度看待时间。时间是我们生活中的一部分,它能够影响我们的感觉和行为。心理学家Zimbardo曾经指出,每个人对时间的感知都是不同的,有些人更关注过去,有些人更关注现在,而有些人则更关注未来。编程中的时间处理也是如此。在处理时间问题时,我们可能关注过去(即计算已经过去多少时间)、关注现来(即计算现在的时间)、或关注未来(即预计还需多少时间)。
std::chrono::duration
正是帮助我们处理这些时间问题的工具。它不仅可以表示时间长度,也可以表示特定时间点到另一个时间点的间隔。与人的感知类似,duration
可以表示"过去多久"(例如5秒前)、“现在”(例如现在到程序开始的时间)、或"未来多久"(例如5秒后)。
std::chrono::duration
的定义是非常灵活的,可以表示各种时间单位。例如,以下是一些常见的duration
类型:
std::chrono::seconds
:以秒为单位的时间长度std::chrono::milliseconds
:以毫秒为单位的时间长度std::chrono::microseconds
:以微秒为单位的时间长度std::chrono::nanoseconds
:以纳秒为单位的时间长度
以下是std::chrono::duration
主要特性的总结:
特性 | 描述 |
类型安全 | std::chrono::duration 的不同单位不能直接混合使用,这避免了由于单位不匹配导致的错误 |
自动类型转换 | 当进行时间单位转换时,std::chrono::duration 可以自动进行,例如从毫秒转换到秒 |
支持算术运算 | 可以对std::chrono::duration 进行加、减、乘、除等算术运算 |
高精度 | 可以表示非常小的时间单位,例如纳秒 |
正如心理学家之所以研究时间感知,因为了解和理解我们如何看待和使用时间,可以帮助我们更好地理解自己并改进我们的生活。同样,熟练掌握std::chrono::duration
的定义和主要特性,能够帮助我们更有效地解决编程中的时间问题。
7.2 duration的常见操作与示例
std::chrono::duration
为我们提供了一系列操作,以便我们能够轻松地处理时间问题。这些操作包括创建时长、执行算术运算、比较时长、将时长转换为不同的单位等。下面,我们将通过一些示例来详细说明这些操作。
7.2.1 创建duration
创建duration的方式非常简单,只需要指定所需的时间长度即可。例如,创建一个表示5秒的duration:
std::chrono::seconds sec(5);
7.2.2 执行算术运算
std::chrono::duration
支持基本的算术运算,包括加法、减法、乘法和除法。例如:
std::chrono::seconds sec1(5); std::chrono::seconds sec2(3); auto sec3 = sec1 + sec2; // sec3 is 8 seconds auto sec4 = sec1 - sec2; // sec4 is 2 seconds
7.2.3 比较duration
std::chrono::duration
还支持比较操作,包括等于、不等于、小于、大于、小于等于和大于等于。例如:
std::chrono::seconds sec1(5); std::chrono::seconds sec2(3); if (sec1 > sec2) { // do something }
7.2.4 转换为不同的单位
通过使用duration_cast,我们可以将一个duration转换为不同的单位。例如:
std::chrono::minutes min(1); auto sec = std::chrono::duration_cast<std::chrono::seconds>(min); // sec is 60 seconds
了解和掌握这些操作,就像心理学家熟悉人的行为和反应一样。我们能够预测和控制人的行为,因为我们理解人的需求和动机。同样,我们能够有效地处理时间问题,因为我们理解std::chrono::duration
的操作和行为。
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)(三)https://developer.aliyun.com/article/1465311