C++日期和时间库
目录
1.引用
2.chrono库
2.1.Duration
2.2.Clock
2.3.TimePoint
2.4.Calendar(c++20)
3.ctime库
4.常见用法
4.1. 获取当前系统时间戳
4.2.计算时间间隔
4.3.格式化输出
4.4.字符串转化为时间戳
4.5.时间戳转为time_point类型
4.6.字面量使用
5.总结
1.引用
unix timestamp(时间戳): 时间戳是计算中广泛使用的日期和时间表示形式。它通过自1970年1月1(Unix 纪元)00:00:00 UTC以来经过的秒数(秒是毫秒、微妙、纳秒的总称)来测量时间,没有因闰秒而进行调整。
C++中处理时间的库主要包括<chrono>
和<ctime>。
2.chrono
库
<chrono>
库是C++11引入的一个标准库,专门用于处理时间点、时间间隔和时钟操作。它提供了高精度的时间点和时长表示,以及时间相关的函数和操作。C++20新增Calendar。
主要包含以下四种类型:
- Duration:表示一个时间间隔,单位可以是秒、毫秒、微秒等。
- Time Point:表示一个时间点,通常基于某个时钟。
- Clock:提供当前时间,通常有三种时钟类型:系统时钟(
system_clock
)、高精度时钟(high_resolution_clock
)和稳定时钟(steady_clock
)。 -
Calendar(c++20)
2.1.Duration
Duration(时间间隔):表示一段时间的长度,这个类模板是时间间隔的抽象表示,可以存储任何时间单位的间隔,比如秒、毫秒、分钟等。std::chrono::duration
允许程序员进行时间间隔的计算,比如加法、减法、比较等,并且可以与时间点(如 std::chrono::time_point
)结合使用来表示具体的时间。
std::chrono::duration
模板类接受两个参数:
- rep:表示时间间隔的数值类型,通常是整数类型,如
int
、long
或long long
。 - period:表示时间间隔的单位,是一个编译时常量表达式,通常是
std::ratio
类型。std::ratio
是一个模板类,用于表示两个整数的比率。标准库中定义了几个常用的std::ratio
类型的别名,如std::nano
(表示纳秒,即10^-9秒)、std::micro
(表示微秒,即10^-6秒)、std::milli
(表示毫秒,即10^-3秒)、std::seconds
(表示秒)、std::minutes
(表示分钟)、std::hours
(表示小时)等。
//define in std::chrono namspace
/// `chrono::duration` represents a distance between two points in time
template<typename _Rep, typename _Period = ratio<1>>
class duration;
//库中预先定义了常用的时间长度
//示例
std::chrono::duration<int, std::milli> duration1(500);
std::chrono::duration<double, std::nano> duration2(1.5);
std::chrono::duration<int, std::micro> duration3 = duration1 + duration2; // 表示501.5微秒
std::chrono::duration<int, std::milli> duration4 = duration1 * 2; // 表示1000毫秒
std::chrono::duration<double, std::milli> duration5 = duration2 / 2; // 表示0.75毫秒
为了方便使用,标准库为常见的时间单位提供了 std::chrono::duration
的特化版本:
- 纳秒(nanoseconds):
std::chrono::nanoseconds
- 微秒(microseconds):
std::chrono::microseconds
- 毫秒(milliseconds):
std::chrono::milliseconds
- 秒(seconds):
std::chrono::seconds
- 分钟(minutes):
std::chrono::minutes
- 小时(hours):
std::chrono::hours
这些特化版本简化了时间单位的表示,使得程序员无需手动指定 rep
和 period
参数。
示例如下:
#include <iostream>
#include <chrono>
int main() {
// 定义一个表示5秒的duration
std::chrono::duration<int, std::ratio<1>> five_seconds(5);
// 定义一个表示200毫秒的duration
std::chrono::milliseconds two_hundred_milliseconds(200);
// 将秒转换为毫秒
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(five_seconds);
std::cout << "5秒等于 " << milliseconds.count() << " 毫秒。" << std::endl;
return 0;
}
在这个例子中,我们定义了两个 std::chrono::duration
对象,一个表示5秒,另一个表示200毫秒。然后,我们使用 std::chrono::duration_cast
将5秒转换为毫秒,并输出结果。
2.2.Clock
- 时钟(clock):表示一个可以测量时间的设备,提供了当前时间点(now)和时间点之间的差值(time_since_epoch)等方法。chrono库提供了三种时钟,分别是:
- 系统时钟(system_clock):表示当前系统范围的实时日历时钟,通常与系统的钟同步。它可以用于表示日期和时间,以及与其他系统交互。
- 稳定时钟(steady_clock):表示一个单调递增的时钟,不受系统时间的调整或修改影响。它可以用于测量时间间隔,以及实现定时器和延时等功能。
- 高分辨率时钟(high_resolution_clock):表示一个具有最高精度的时钟,通常是系统时钟或稳定时钟的别名(using high_resolution_clock = system_clock;)。它可以用于测量极短的时间间隔,以及实现性能分析等功能。
- now --成员函数,放回当前时钟的时间点
1) std::chrono::system_clock
它表示系统范围的实时时钟。这个时钟类提供了访问系统当前时间点的功能,并且允许将时间点转换为 time_t
类型(通常用于表示日历时间)以及进行时间点之间的算术运算。使用 std::chrono::system_clock::now()
可以获取当前的系统时间点,返回类型是 std::chrono::system_clock::time_point
。
示例代码:
#include <iostream>
#include <chrono>
#include <ctime>
int main() {
// 获取当前系统时间点
auto now = std::chrono::system_clock::now();
// 将当前系统时间点转换为 time_t 类型
std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
// 将 time_t 类型转换为 tm 结构,用于格式化输出
std::tm* now_tm = std::localtime(&now_time_t);
// 输出当前时间
std::cout << "当前时间是: "
<< (now_tm->tm_year + 1900) << "-"
<< (now_tm->tm_mon + 1) << "-"
<< now_tm->tm_mday << " "
<< now_tm->tm_hour << ":"
<< now_tm->tm_min << ":"
<< now_tm->tm_sec
<< std::endl;
// 创建一个表示10秒后的时间点
auto ten_seconds_later = now + std::chrono::seconds(10);
// 输出10秒后的时间(注意:这里只是简单地将秒数加上,没有考虑闰秒等复杂情况)
std::time_t ten_seconds_later_time_t = std::chrono::system_clock::to_time_t(ten_seconds_later);
std::tm* ten_seconds_later_tm = std::localtime(&ten_seconds_later_time_t);
std::cout << "10秒后的时间是: "
<< (ten_seconds_later_tm->tm_year + 1900) << "-"
<< (ten_seconds_later_tm->tm_mon + 1) << "-"
<< ten_seconds_later_tm->tm_mday << " "
<< ten_seconds_later_tm->tm_hour << ":"
<< ten_seconds_later_tm->tm_min << ":"
<< ten_seconds_later_tm->tm_sec
<< std::endl;
return 0;
}
在这个例子中,我们获取了当前的系统时间点,并将其转换为 time_t
类型,然后格式化为人类可读的日期和时间格式输出。接着,我们创建了一个表示当前时间点之后10秒的新时间点,并同样进行了格式化输出。需要注意的是,这里的10秒后的时间计算是简单的秒数相加,并没有考虑诸如闰秒等复杂的时间调整情况。
2) std::chrono::steady_clock
它表示一个稳定的、单调递增的时钟。这个时钟类的主要特点是它不受系统时间调整(如用户手动更改系统时间)的影响,因此非常适合用于测量时间间隔,例如性能分析、计时器等场景。使用 std::chrono::steady_clock::now()
可以获取当前的稳定时间点,返回类型是 std::chrono::steady_clock::time_point
。
示例如下:
#include <iostream>
#include <chrono>
int main() {
// 记录开始时间
auto start = std::chrono::steady_clock::now();
// 在这里执行一些代码,例如循环计算
for (int i = 0; i < 1000000; ++i) {
// 一些计算或操作
}
// 记录结束时间
auto end = std::chrono::steady_clock::now();
// 计算执行时间并转换为毫秒
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
// 输出执行时间
std::cout << "Execution time: " << duration.count() << " milliseconds" << std::endl;
return 0;
}
在这个例子中,我们使用 std::chrono::steady_clock
来测量一个循环计算代码段的执行时间,并将结果转换为毫秒后输出。由于 std::chrono::steady_clock
的稳定性和单调性,我们可以确保测量得到的时间间隔是准确的。
3) std::chrono::steady_clock
它旨在提供一个具有最高可用精度的时钟。然而,需要注意的是,std::chrono::high_resolution_clock
并不总是代表实际的最高分辨率时钟,而是代表在当前实现中可用的最高分辨率时钟。换句话说,它的行为可能因编译器和平台而异。使用 std::chrono::high_resolution_clock::now()
可以获取当前的高精度时间点,返回类型是 std::chrono::high_resolution_clock::time_point
。
示例如下:
#include <iostream>
#include <chrono>
int main() {
// 记录开始时间
auto start = std::chrono::high_resolution_clock::now();
// 在这里执行一些代码,例如循环计算
for (int i = 0; i < 1000000; ++i) {
// 一些计算或操作
}
// 记录结束时间
auto end = std::chrono::high_resolution_clock::now();
// 计算执行时间并转换为纳秒(注意:这里可能会因为精度问题而有所偏差)
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
// 输出执行时间(转换为毫秒以便更易于理解,尽管我们是以纳秒为单位测量的)
std::cout << "Execution time: " << duration.count() / 1e6 << " milliseconds" << std::endl;
return 0;
}
在这个例子中,我们使用 std::chrono::high_resolution_clock
来测量一个循环计算代码段的执行时间,并将结果转换为毫秒后输出(尽管我们实际上是以纳秒为单位测量的,但为了方便理解,我们将其转换为毫秒)。然而,需要注意的是,由于 std::chrono::high_resolution_clock
的精度可能受到硬件和操作系统的限制,因此测量得到的时间可能会有一定的偏差。
2.3.TimePoint
- 时间点(time_point):表示一个特定时刻,由一个时钟和一个时间间隔组成。例如,
std::chrono::system_clock::now()
表示系统时钟的当前时间点,std::chrono::steady_clock::now()
表示稳定时钟的当前时间点,等等。chrono库还提供了一些常用的时间点别名,如std::chrono::system_clock::time_point
,std::chrono::steady_clock::time_point
,std::chrono::high_resolution_clock::time_point
等。 - time_since_epoch 返回到epoch的时间间隔Duration
2.4.Calendar(c++20)
- 日期类,用来对日期时间进行比较。
using namespace std::chrono_literals;
//使用字面量 ""y ""d(C++20)
auto ymd1 = 2023y / std::chrono::November / 10d; // 2023-11-10
auto ymd2 = 2023y / std::chrono::September / 10d; // 2023-9-10
if(ymd1 > ymd2) {
// ymd1 > ymd2
std::cout << "ymd1 > ymd2" << std::endl;
}
3.ctime库
<ctime>
库提供了与时间相关的类型和函数,包括对time_t
类型的操作,以及转换时间和日期的函数。它使用time_t
类型来表示时间点,并提供了将时间转换为字符串的函数。
-
核心类型
clock_t
:用于表示从程序启动以来经过的CPU时间。time_t
:表示从Unix纪元(1970年1月1日00:00:00 UTC)以来的秒数。tm
结构:表示本地或格林威治标准时间的结构。
-
常用函数
time(NULL)
:获取当前时间,返回time_t
类型的值。localtime(&time_t)
:将time_t
类型的时间转换为本地时间tm
结构。gmtime(&time_t)
:将time_t
类型的时间转换为UTC时间tm
结构。asctime(&tm)
:将tm
结构转换为字符串形式。strftime(char*, size_t, const char*, const tm*)
:格式化时间。
-
常见用法
- 获取当前时间并转换为本地时间:
std::tm* local_time = std::localtime(&now);
- 格式化输出时间:
char buffer[80]; std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local_time);
- 获取当前时间并转换为本地时间:
示例如下:
#include <iostream>
#include <ctime>
int main() {
// 获取当前时间的 time_t 表示
time_t currentTime = time(nullptr);
// 将 time_t 转换为 tm 结构体
tm* localTime = localtime(¤tTime);
// 打印日期和时间
std::cout << "Current date and time: "
<< (localTime->tm_year + 1900) << '-'
<< (localTime->tm_mon + 1) << '-'
<< localTime->tm_mday << ' '
<< localTime->tm_hour << ':'
<< localTime->tm_min << ':'
<< localTime->tm_sec
<< std::endl;
return 0;
}
请注意,tm_year
成员表示自1900年以来的年数,因此需要加上1900来得到实际的年份。同样地,tm_mon
成员表示月份(从0开始计数),因此需要加上1来得到实际的月份。
4.常见用法
4.1. 获取当前系统时间戳
//获取系统时间戳,实例化系统时钟
std::chrono::system_clock clock;
std::chrono::system_clock::time_point now = clock.now();
std::chrono::_V2::system_clock::duration d = now.time_since_epoch();
//纳秒单位时间戳
std::cout << "timestamp: " << d.count() << std::endl;
//转化为秒单位
std::chrono::seconds t = std::chrono::duration_cast<std::chrono::seconds>(d);
std::cout << "sec: " << t.count() << std::endl;
//简化写法
// std::chrono::system_clock clock;
// auto t = std::chrono::duration_cast<std::chrono::seconds>(
// clock.now().time_since_epoch()).count();
// std::cout << "sec: " << t << std::endl;
4.2.计算时间间隔
const auto start = std::chrono::high_resolution_clock::now();
//do something
std::this_thread::sleep_for(std::chrono::seconds(1));
const auto end = std::chrono::high_resolution_clock::now();
auto duration = start - end;
//1000118000ns 1000ms 1s
std::cout << duration.count() << "ns " <<
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()<< "ms " <<
std::chrono::duration_cast<std::chrono::seconds>(duration).count() << "s " <<
std::endl;
4.3.格式化输出
auto now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
//cur time Thu Nov 9 23:42:38 2023
std::cout << "cur time " << std::ctime(&now_c) << std::endl;
//或者转化为当地时间
//自定义格式输出
tm * t = std::localtime(&now_c);
char buffer[80];
std::strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", t);
//cur time: 2023-11-09 23:42:38
std::cout << "cur time: " << buffer << std::endl;
4.4.字符串转化为时间戳
time_t GetUnixSecFromStr(const std::string &raw_time) {
std::istringstream ss(raw_time);
std::tm tm{};
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S"); //ex:2023-12-22 19:22:23
return std::mktime(&tm);
}
4.5.时间戳转为time_point类型
time_t time;
auto t_point = std::chrono::system_clock::from_time_t(time);
4.6.字面量使用
//使用字面量 c++20 ""y ""d c++11 支持 ""h ""min ""s ""ms ""us
using namespace std::chrono_literals;//在此空间定义字面量
auto s = 60s; // 相当于std::chrno::seconds(60)
std::cout << "sec: " << s.count() << std::endl;
auto min = 1min; // 相当于std::chrono::minutes(1):
std::cout << "min: " << min.count() << std::endl;
5.总结
std::chrono时间库在不同平台上都具备良好的兼容性,无论是Windows、Linux还是其他操作系统,都可以使用该库进行时间处理,使代码具备良好的可移植性。该库提供了丰富的时间单位和精度选项,适应不同场景下的时间计算需求。无论是秒、毫秒、微秒还是纳秒的时间单位,都可以很方便地应用于代码中。而且std::chrono时间库提供了不同类型的时钟,如系统时钟(system_clock)、稳定时钟(steady_clock)和高分辨率时钟(high_resolution_clock),可以根据具体需求选择合适的时钟类型。
进一步学习和参考C++ std::chrono时间库的推荐资源:
- 官方文档:可以查阅C++标准库的官方文档,其中包含了std::chrono时间库的详细说明和示例代码。官方文档可以帮助深入了解每个类、函数和成员的用法和语义。
- C++ Reference:C++ Reference是一个权威的C++参考网站,提供了std::chrono时间库的详细文档和示例代码。可以在该网站上查找特定类、函数或成员,并了解它们的用法和示例。
- 推荐书籍:《C++ Concurrency in Action: Practical Multithreading》和《Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14》。