C++ 日期 & 时间
在现代 C++ 中,处理日期和时间主要有两大途径:
- 传统 C 接口(
<ctime>
) - C++11 及之后的
<chrono>
库(并在 C++20 增强了日历/格式化支持)
下面分别介绍它们的用法,并结合示例说明如何获取、表示、计算、格式化和解析时间。
1. 传统 C 接口(<ctime>
)
#include <ctime>
#include <iostream>
int main() {
// 获取当前时间(自 1970-01-01 00:00:00 UTC 起的秒数)
std::time_t t = std::time(nullptr);
// 转为本地时间结构
std::tm local = *std::localtime(&t);
// 格式化输出
char buf[64];
std::strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S", &local);
std::cout << "本地时间: " << buf << "\n";
// UTC 时间
std::tm utc = *std::gmtime(&t);
std::strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S UTC", &utc);
std::cout << "UTC 时间: " << buf << "\n";
}
std::time_t
:通常是秒级别的整数类型。std::localtime
/std::gmtime
:将time_t
转为std::tm
(年、月、日、时、分、秒等字段)。std::strftime
:格式化std::tm
,支持常见%Y, %m, %d, %H, %M, %S
等控制符。
缺点:精度到秒,不便做高精度计时;易受时区/夏令时影响;接口不够类型安全。
2. C++11 <chrono>
库
2.1 时钟(Clocks)、时刻(Time Point)与持续时间(Duration)
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono;
// 以高精度时钟获取当前时刻
auto t0 = high_resolution_clock::now();
// 模拟耗时操作
for (volatile int i = 0; i < 1000000; ++i) {}
auto t1 = high_resolution_clock::now();
// 计算两次时刻之间的持续时间
auto dt = t1 - t0; // dt 是一个 duration
// 转换为毫秒
auto ms = duration_cast<milliseconds>(dt).count();
std::cout << "耗时: " << ms << " ms\n";
}
- 时钟(
system_clock
,steady_clock
,high_resolution_clock
)system_clock
:可转换为time_t
,对应系统时间。steady_clock
:单调递增,适合做精确计时,不受系统时间调整影响。
time_point<Clock>
:某个时刻;与Clock::now()
配合使用。duration<Rep, Period>
:时间间隔;可通过duration_cast
转换到所需单位。
2.2 时间点与传统接口互转
// system_clock <-> time_t
auto now_tp = std::chrono::system_clock::now();
std::time_t now_t = system_clock::to_time_t(now_tp);
std::tm local = *std::localtime(&now_t);
// 从 time_t 回到 time_point
auto tp2 = system_clock::from_time_t(now_t);
3. C++20 日历与格式化(<chrono>
扩展)
C++20 在 <chrono>
中引入了对日历(calendar)和文本格式化的支持。
#include <chrono>
#include <iostream>
#include <format>
int main() {
using namespace std::chrono;
// 获取当前系统时刻并转换为日历日期
auto today = floor<days>(system_clock::now());
year_month_day ymd = today;
std::cout << "日期: "
<< int(ymd.year()) << "-"
<< unsigned(ymd.month()) << "-"
<< unsigned(ymd.day()) << "\n";
// 格式化输出 datetime
auto now = system_clock::now();
std::cout << std::format("现在是 {:%Y-%m-%d %H:%M:%S}\n", now);
}
std::chrono::year_month_day
、year_month_weekday
等类型,支持日历运算(加减月、年等)。std::format
(C++20)结合<chrono>
支持直接格式化输出时间点。
4. 解析日期字符串
4.1 传统方式:std::get_time
#include <sstream>
#include <iomanip>
#include <iostream>
int main() {
std::string s = "2025-07-09 15:30:45";
std::istringstream in(s);
std::tm tm = {};
in >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
if (in.fail()) {
std::cerr << "解析失败\n";
} else {
std::time_t t = std::mktime(&tm);
std::cout << "解析后的 timestamp: " << t << "\n";
}
}
4.2 C++20:std::chrono::parse
(配合 <format>
扩展库)
(注意:目前 GCC/Clang 下部分支持库才有)
#include <chrono>
#include <iostream>
#include <format> // 或 <chrono> 中的 parse
using namespace std::chrono;
int main() {
std::string s = "2025-07-09";
year_month_day ymd;
std::istringstream in(s);
in >> parse("%F", ymd); // %F 等同于 %Y-%m-%d
std::cout << "年: " << int(ymd.year())
<< " 月: " << unsigned(ymd.month())
<< " 日: " << unsigned(ymd.day()) << "\n";
}
5. 常见操作示例
操作 | 示例代码片段 |
---|---|
加/减 天数 | ymd += days{7}; |
比较两个时间点 | if (t1 < t2) … |
定时执行(sleep) | std::this_thread::sleep_for(milliseconds{100}); |
计算某月的天数 | days{year / month / 1}.end_of_month().day() (C++23) |
6. 小结
- 若仅需简单获取和格式化当前时间,传统
<ctime>
足够; - 若需高精度、类型安全的计时、时间算术,优先使用
<chrono>
; - 在 C++20 环境下,享受日历类型与直接格式化的便利;
- 对复杂时区处理或日历算法需求,可考虑第三方库,如 Howard Hinnant date 库、ICU 等。
掌握以上内容,便能在 C++ 各种场景下灵活、精准地处理日期与时间。