1. 引言
1.1. std::chrono库的主要功能
std::chrono
是C++标准库中的一个组件,用于表示和处理时间。其功能就像是心理学中的感知系统,它可以为我们捕捉、量化并操作抽象的时间概念。这就如同我们的大脑可以理解和感知周围环境的时间流逝一样,这种感知和理解能力是人类进行日常活动所必需的。
如同马斯洛的需求层次理论中,生理需求位于最底层,时间感知就是计算机程序在处理各种任务时的基础需求,如果没有这个能力,计算机程序将无法进行任何有效的操作。
std::chrono
库主要包含以下功能:
- 时间点:表示特定的时间点,比如当前的时间。这如同人们通过记忆可以回忆起特定的时刻。
- 时间段:表示时间的长度,比如1秒,1分钟,1小时等。这如同人们能够感知时间的流逝,理解"早","晚"等概念。
- 时钟:用于获取当前的时间点,有三种类型的时钟:system_clock,steady_clock和high_resolution_clock。这如同人们通过看表来知道现在的具体时间。
为了更好的理解这些功能,让我们看一下下面的表格:
类名 | 描述 | 对应的心理学概念 |
std::chrono::system_clock | 系统的实际时间,可能会受到系统时间调整的影响 | 外部环境对人的影响 |
std::chrono::steady_clock | 稳定的时钟,时间从不调整 | 稳定、可靠的心理状态 |
std::chrono::high_resolution_clock | 提供最小的可表示的时间间隔 | 细微的心理变化 |
std::chrono::time_point | 表示特定的时间点 | 特定的记忆 |
std::chrono::duration | 表示时间的长度 | 时间的感知 |
接下来,我们将详细探讨std::chrono
库的各种子类如何使用,以及如何在实际编程中应用这些知识。
2. std::chrono库的子类介绍与应用
2.1. std::chrono::system_clock的用法和示例
我们的生活在时间的流逝中不断推进,这个自然的过程在C++中被封装在了std::chrono::system_clock
这个类中。我们如同航海者使用指南针导航一样,可以借助system_clock
在编程的海洋中导航。
std::chrono::system_clock
是一个代表系统广泛使用的实时钟的类。它表示当前的墙上时间,从中可以获得当前时间,也可以在时间点上执行算术运算。
获取当前时间
你可以想象std::chrono::system_clock
就像是一个不断向前的时间车轮。要获取当前时间,你只需要使用now()
成员函数。看下面的代码:
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
这就像是在你的时间旅行中按下暂停按钮,捕捉到了一个时间点。这个点可以被保存,可以用来与其他时间点做比较,或者用作时间运算。
从time_point获取具体时间
system_clock::time_point
表示一个时间点。但是我们通常需要更人性化的表达方式,比如年、月、日、小时、分钟和秒。这时候,我们可以像打开一个礼物盒一样,打开这个time_point
,取出我们需要的信息。请看下面的代码:
std::time_t tt = std::chrono::system_clock::to_time_t(now); std::tm* ptm = std::localtime(&tt); std::cout << "Current time is: " << std::put_time(ptm,"%c") << std::endl;
这段代码就像是在一个连续的时间轴上拨动时间,找到那个特殊的瞬间,并用人们熟悉的方式表达出来。
进行时间运算
有时候,我们会需要对时间进行一些计算,比如计算从现在开始的某个时间点是何时。这时候,我们就像是在时间的河流中划动桨板,按照我们的意愿改变时间的前进。请看下面的代码:
std::chrono::system_clock::time_point in_an_hour = std::chrono::system_clock::now() + std::chrono::hours(1);
这就像我们在时间的河流中向前推进了一小时。
功能 | 代码示例 |
获取当前时间 | std::chrono::system_clock::now(); |
从time_point 获取具体时间 |
std::chrono::system_clock::to_time_t(now); std::localtime(&tt); std::put_time(ptm,"%c"); |
进行时间运算 | std::chrono::system_clock::now() + std::chrono::hours(1); |
通过上述的学习和比喻,你可能已经对std::chrono::system_clock
有了一些了解。接下来,我们将通过实际的示例,来深入探讨和使用这个强大的类。
2.2. std::chrono::steady_clock的用法和示例
想象一下,你正在烹饪一道需要精确时间的菜肴,你可能需要一个计时器来确保你的食物得到正确的烹饪时间。在这种情况下,你不希望因为 daylight saving time(夏令时)或者系统时钟调整等导致你的时间计算出错。在C++中,这就是std::chrono::steady_clock
的用途。
std::chrono::steady_clock
是一个表示物理时间流逝的时钟,不受任何外部因素(如用户修改系统时间,夏令时等)的影响。就像是你的厨房里的计时器,它按照一致的速度前进,不会突然快了或慢了。
获取当前时间
和std::chrono::system_clock
一样,你可以通过调用now()
函数来获取当前的std::chrono::steady_clock::time_point
。看下面的代码:
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
这就像你在开始烹饪时按下计时器的开始按钮。
计算经过的时间
在你的菜肴烹饪完成后,你可能会想知道实际的烹饪时间。同样,在C++中,你可以通过减去开始时间来得到一个std::chrono::steady_clock::duration
,这个duration
表示了一个时间段。看下面的代码:
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); std::chrono::steady_clock::duration elapsed = end - start;
这就像你在结束烹饪时查看计时器,看你的食物烹饪了多长时间。
转换时间单位
std::chrono::steady_clock::duration
给出的默认时间单位可能并不是你想要的。比如,默认可能给你的是微秒级别的时间,但你可能想要以秒为单位的时间。这时候,你就需要转换时间单位。看下面的代码:
long long elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>(elapsed).count();
这就像你将计时器的显示从“分钟:秒”转换为“总秒数”。
功能 | 代码示例 |
获取当前时间 | std::chrono::steady_clock::now(); |
计算经过的时间 | std::chrono::steady_clock::now() - start; |
转换时间单位 | std::chrono::duration_cast<std::chrono::seconds>(elapsed).count(); |
通过对std::chrono::steady_clock
的学习,你可以像烹饪大师一样掌握时间,在编程的厨房里烹饪出美味的代码。
2.3. std::chrono::high_resolution_clock的用法和示例
考虑到现实生活中,我们有时候需要对时间进行极度精确的测量,比如科学实验或者高精度事件的时间戳,std::chrono::high_resolution_clock
就像是我们手中的精密计时器,提供了尽可能高的时间分辨率。
std::chrono::high_resolution_clock
是一个特殊的时钟,它提供了最高的可用时间分辨率。它通常是std::chrono::system_clock
或std::chrono::steady_clock
中的一个类型别名,具体取决于具体平台和库实现。
获取当前时间
使用std::chrono::high_resolution_clock
获取当前时间就像我们按下精密计时器的按钮,记录下现在的时刻。如下所示:
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
计算经过的时间
我们可以通过比较两个时间点来计算经过的时间,就像精密计时器可以为我们提供精确到纳秒级别的时间间隔。请参考以下代码:
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); std::chrono::high_resolution_clock::duration elapsed = end - start;
转换时间单位
和其他时钟一样,我们可能需要将std::chrono::high_resolution_clock::duration
的时间单位进行转换,使其满足我们的需求。例如,我们可以将时间间隔转换为微秒,如下所示:
long long elapsed_microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
这就像你的精密计时器可以以各种不同的时间单位来显示测量结果。
功能 | 代码示例 |
获取当前时间 | std::chrono::high_resolution_clock::now(); |
计算经过的时间 | std::chrono::high_resolution_clock::now() - start; |
转换时间单位 | std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count(); |
通过理解和应用std::chrono::high_resolution_clock
,我们可以像使用精密计时器一样,在编程世界里精确地测量和控制时间。
3. 获取时间戳 (Obtaining Timestamps)
3.1. 使用std::chrono::system_clock::now获取当前时间戳
在我们的日常生活中,我们依赖时间去安排我们的日程,设置闹钟,甚至计算烹饪的时间。在编程的世界里,时间同样重要,而std::chrono::system_clock::now
就是我们获取当前时间戳的工具。
auto now = std::chrono::system_clock::now();
这就像你打开手机看看现在几点一样简单。从心理学的角度看,人类对时间的感知并不准确,我们的大脑经常会过度估计或低估实际的时间流逝。但是,计算机是完全精确的,它们对时间的把握可以精确到微秒级。
获取当前时间点的详细日期和时间
有时候,我们需要知道更多的信息,比如当前的具体日期和时间。为此,我们可以使用C++的time_point转换为time_t,然后再使用标准库中的localtime
函数来获取详细信息。
auto now = std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(now); std::tm* now_tm = std::localtime(&t);
这就像你从简单地知道现在是下午转变为知道现在是下午3点25分。在编程中,这个功能非常有用,比如在记录事件或者在debug中打印出具体的时间点。
获取时间戳的应用
获取时间戳的应用广泛而且重要。例如,在性能调优时,你需要知道代码执行的具体时间,或者在日志记录时,你需要记录事件发生的准确时间。你可以将std::chrono::system_clock::now
想象成一个永不停息的时钟,它可以精确地告诉你现在的时间。当你需要测量一段代码的运行时间时,只需要在代码开始和结束时各取一个时间戳,然后将它们相减,就可以得到运行时间。
人们对于时间的需求,从基本的查看时间,到计算间隔,再到记录精确的时间戳,编程语言都提供了强大的工具来满足。在C++中,std::chrono::system_clock::now
就是这样一个强大的工具。
3.2. 时间戳的转换和应用
在许多场景中,我们需要将时间戳(Timestamp)转换为更容易理解和使用的格式。同时,我们可能需要在不同的时间单位之间进行转换。好在C++中的std::chrono
库提供了丰富的函数和类来满足这些需求。
时间戳转换为具体日期和时间
获取的时间戳通常是从某个参考点(通常是Epoch,1970年1月1日)开始计算的毫秒数。为了将这个时间戳转换为人们习惯的日期和时间格式,我们可以利用std::chrono
库提供的接口将std::chrono::system_clock::time_point
转换为std::time_t
,然后使用C语言的标准库函数将其转换为struct tm
,最后可以使用std::strftime
将struct tm
转换为字符串。
auto now = std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(now); std::tm* now_tm = std::localtime(&t); char buffer[80]; std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", now_tm); std::cout << "Current time: " << buffer << std::endl;
这就像我们将一个长篇的数字字符串(比如一串电话号码)转换成更容易理解的格式,比如在适当的位置添加了短横线。
时间单位的转换
在std::chrono
库中,我们可以很容易地在不同的时间单位之间转换。这种转换类似于我们在长度、重量等不同的物理单位之间进行转换。比如,我们可以很容易地将std::chrono::seconds
转换为std::chrono::milliseconds
:
std::chrono::seconds sec(1); auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(sec);
通过这样的方式,我们可以将代码中的时间管理变得更加灵活,满足各种精度的需求。
时间戳在实际问题中的应用示例
在实际的编程问题中,时间戳的应用是广泛的。例如,我们可以使用时间戳来度量一段代码的执行时间,也可以在日志记录中添加时间戳,来追踪事件发生的时间。
auto start = std::chrono::high_resolution_clock::now(); // Code to be measured. auto end = std::chrono::high_resolution_clock::now(); auto elapsed = end - start; std::cout << "Elapsed time: " << elapsed.count() << "ns\n";
在这个示例中,我们使用std::chrono::high_resolution_clock::now
获取代码开始和结束的时间,然后计算出代码执行所需的时间。这就像我们使用秒表来测量运动员的速度一样,可以帮助我们更好地理解和优化代码的性能。
3.3. 时间戳在实际问题中的应用示例
在软件开发中,时间戳的使用几乎无处不在,例如性能测量、日志记录、时间戳计算等。在这一部分,我们将探讨一些常见的时间戳应用示例。
性能测量
当你需要优化代码以提高执行速度时,时间戳的使用就显得尤为重要。可以在代码块的开始和结束处获取时间戳,然后计算执行时间:
auto start = std::chrono::high_resolution_clock::now(); // ... Your code to measure ... auto stop = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); std::cout << "Time taken by function: " << duration.count() << " microseconds" << std::endl;
这就像你使用秒表来测量一个运动员完成赛跑所需的时间,从而分析他的运动表现并寻找改进的地方。
日志记录
在日志记录中,时间戳可以帮助我们跟踪事件的发生时间。当我们查看日志以调试或理解系统行为时,知道事件发生的准确时间通常非常有用。
auto now = std::chrono::system_clock::now(); std::time_t now_c = std::chrono::system_clock::to_time_t(now); std::cout << "Log event happened at " << std::ctime(&now_c);
时间戳计算
有时候,我们需要进行基于时间的计算,比如计算两个日期之间的差值,或者添加特定的时间量。这时,我们可以使用std::chrono::duration
来执行这些操作。
auto t1 = std::chrono::system_clock::now(); // ... some code ... auto t2 = std::chrono::system_clock::now(); auto duration = t2 - t1; std::cout << "Duration between t1 and t2: " << duration.count() << " seconds\n";
以上这些只是时间戳在实际问题中的一些应用示例。使用C++的std::chrono
库,你可以进行更复杂和高级的时间处理操作。
4. 计时器的实现
4.1 使用std::chrono
库实现基本计时器
在编程中,我们经常需要测量代码的执行时间,比如,对比两种算法的性能或者查找代码中的性能瓶颈。C++的std::chrono
库为我们提供了这样的工具。
基本计时器实现
我们首先需要理解,计时器 (Timer) 可以被比作是心理学中的“定时器”。当人们需要专注于某项任务时,他们会设定一个定时器来保持专注并度量时间。这与编程中使用计时器的动机非常相似。我们希望对程序的运行时间有个准确的度量,以此来优化我们的代码。
在C++中,一个基本的计时器可以通过std::chrono
库中的high_resolution_clock
来实现。代码示例如下:
#include <iostream> #include <chrono> int main() { auto start = std::chrono::high_resolution_clock::now(); // 开始计时 // 你需要测量的代码块 auto end = std::chrono::high_resolution_clock::now(); // 结束计时 std::chrono::duration<double> diff = end-start; // 计算时间差 std::cout << "Code executed in " << diff.count() << " seconds" << std::endl; return 0; }
在上述代码中,start
和end
都是std::chrono::time_point
对象,表示一个时间点。high_resolution_clock::now()
函数返回当前时间点。然后,我们通过计算end
和start
之间的差值,得到代码执行的时间。最后,使用count()
函数以秒为单位打印出运行时间。
这就像是你设定了一个心理学中的定时器,你知道何时开始,何时结束,并且你可以测量这段时间。
在接下来的章节中,我们将详细介绍更高级的计时器功能。
4.2 高级计时器功能与实现(例如:暂停、重置)
计时器的暂停与恢复
在现实生活中,我们的计时器有时需要暂停并稍后恢复。比如说,你正在烹饪并根据食谱倒计时,突然有人敲门,你需要停下来应对。在这种情况下,你会暂停计时器,然后在事情处理完后恢复计时。同样,我们在编程中也会遇到类似的情况。
在C++中,我们可以通过以下方法来实现计时器的暂停和恢复功能:
#include <iostream> #include <chrono> class Timer { private: bool running; std::chrono::time_point<std::chrono::high_resolution_clock> start_time, end_time; public: Timer() : running(false) {} void start() { running = true; start_time = std::chrono::high_resolution_clock::now(); } void stop() { if (running) { end_time = std::chrono::high_resolution_clock::now(); running = false; } } double elapsed() { if (running) { return std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - start_time).count(); } else { return std::chrono::duration<double>(end_time - start_time).count(); } } void reset() { running = false; } }; int main() { Timer timer; timer.start(); // Some code timer.stop(); std::cout << "Elapsed time: " << timer.elapsed() << " seconds." << std::endl; // Continue with the timer timer.start(); // Some code timer.stop(); std::cout << "Total elapsed time: " << timer.elapsed() << " seconds." << std::endl; return 0; }
上述代码中定义了一个名为Timer
的类,其中包含了start()
, stop()
, elapsed()
, 和 reset()
这些方法。start()
用于开始或恢复计时,stop()
用于暂停计时,elapsed()
用于获取已过去的时间,而reset()
则用于重置计时器。这就像我们生活中使用的实际计时器一样,能进行开始、暂停、恢复和重置等操作。
通过以上方式,我们不仅增强了计时器的功能,更为我们的编程工作提供了更灵活的时间度量工具。
C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)(二)https://developer.aliyun.com/article/1465310