在 C++ 中,如果我们想获取电脑当前的真实日期和时间(即现在是哪一年几月几日、几点几分几秒),最常用的做法是使用 <chrono> 头文件中的 system_clock 配合 <ctime> 中的时间转换函数。
拿到系统时间点之后,我们既可以将其格式化成 "2026-10-24 15:30:00" 这样的常见日期字符串,也可以单独提取出里面的年月日、星期和时分秒。
获取当前时间并格式化输出
调用 std::chrono::system_clock::now() 就能拿到当前的系统时间点。不过要注意,它返回的是一个 time_point 时间点对象,默认不能直接当成日期字符串打印出来。
由于 C++11 引入的 <chrono> 主要负责高精度计时,本身没有提供直接拆解 “年月日” 的函数,因此我们可以结合 <ctime> 与 <iomanip> 头文件,按固定步骤完成转换与格式化输出。
语法:
std::time_t t = std::chrono::system_clock::to_time_t(时间点);
std::tm* p = std::localtime(&t);
std::cout << std::put_time(p, "格式字符串");说明:
上面这 3 行代码依次完成了 3 步转换:
- 转换为 time_t 类型:调用
system_clock::to_time_t(),将系统时间点转换为 C 风格的时间值std::time_t。 - 拆解为本地日历时间:调用
<ctime>中的std::localtime(&t)(注意变量前要加取地址符&),根据电脑当前所在的时区拆解出包含年、月、日、时、分、秒的结构体指针p。 - 按格式输出:调用
<iomanip>中的std::put_time(),按照指定的格式字符串打印日期时间。这套写法在主流编译器上兼容性最好,平时直接当成固定组合使用即可。
示例 1:按标准格式输出当前时间
#include <chrono>
#include <ctime> // 提供 std::localtime()
#include <iomanip> // 提供 std::put_time()
#include <iostream>
int main() {
// 获取当前系统时间点
auto now = std::chrono::system_clock::now();
// 转为本地日历时间结构体
std::time_t t = std::chrono::system_clock::to_time_t(now);
std::tm* p = std::localtime(&t);
std::cout << std::put_time(p, "%Y-%m-%d %H:%M:%S") << '\n';
return 0;
}运行结果如下。
2026-10-24 15:30:00分析:
在这个例子中,我们先按固定步骤拿到了本地时间指针 p,再通过 std::put_time() 将其按 "%Y-%m-%d %H:%M:%S" 格式打印出来。由于程序读取的是运行那一刻的真实电脑时间,当你在自己电脑上运行时,看到的就是当前的最新日期和时间。
在格式字符串 "%Y-%m-%d %H:%M:%S" 中,用到的 6 个格式符直接对应英文单词首字母(注意严格区分大小写),具体含义如下表所示。
| 格式符 | 英文来源 | 含义说明 | 输出示例 |
|---|---|---|---|
| %Y | Year(年) | 4 位数的完整年份 | 2026 |
| %m | month(月) | 2 位数的月份,不足 2 位自动补 0(01~12) | 10 |
| %d | day(日) | 2 位数的日期,不足 2 位自动补 0(01~31) | 24 |
| %H | Hour(时) | 24 小时制的小时(00~23) | 15 |
| %M | Minute(分) | 2 位数的分钟(00~59) | 30 |
| %S | Second(秒) | 2 位数的秒数(00~59) | 00 |
提示 在咱们配置好的 VSCode(GCC)或在线编译器下,上面的代码可以直接编译运行。如果小伙伴们在 Windows 上使用 Visual Studio(MSVC)编译,遇到 localtime 相关的 C4996 安全报错,可以在代码最顶部(所有 #include 之前)加上一行 #define _CRT_SECURE_NO_WARNINGS 来解决。
自定义常见的日期时间格式
掌握了上面的 6 个基本格式符后,我们只需要调整格式字符串里的连接符号或组合顺序,就能把同一个时间指针 p 格式化成各种常见的显示样式。请看下面例子。
示例 2:输出不同格式的日期时间
#include <chrono>
#include <ctime>
#include <iomanip>
#include <iostream>
int main() {
auto now = std::chrono::system_clock::now();
std::time_t t = std::chrono::system_clock::to_time_t(now);
std::tm* p = std::localtime(&t);
std::cout << std::put_time(p, "%Y-%m-%d") << '\n';
std::cout << std::put_time(p, "%Y/%m/%d") << '\n';
std::cout << std::put_time(p, "%H:%M:%S") << '\n';
std::cout << std::put_time(p, "%Y%m%d_%H%M%S") << '\n';
return 0;
}运行结果如下。
2026-10-24
2026/10/24
15:30:00
20261024_153000分析:
在上面代码中,我们只调用了一次 system_clock::now() 和 std::localtime(),接着就能通过 std::put_time() 输出横杠日期、斜杠日期、纯时间或常用于日志文件命名的紧凑格式(如 20261024_153000)。遇到个位数的月份或时分秒时(比如早上 8 点 5 分),格式符还会自动在左侧补 0 显示为 08:05。
单独提取年月日与时分秒
有些时候,我们不仅想把时间打印成字符串,还需要单独拿出 “今年是哪一年”、“现在是几月”、“今天是星期几” 的整数值来做条件判断,比如判断今天是不是周末。
前面调用的 std::localtime(&t) 返回的是一个指向 std::tm 类型的结构体指针,我们可以通过箭头运算符 -> 访问它内部的整型成员。常用的成员如下表所示。
| 成员名称 | 表示含义 | 取值范围与换算规则 |
|---|---|---|
| tm_year | 年份偏移量 | 自 1900 年算起的年数,实际年份为 tm_year + 1900 |
| tm_mon | 月份下标 | 范围是 0~11(0 代表 1 月),实际月份为 tm_mon + 1 |
| tm_mday | 当月几号 | 范围是 1~31,直接表示当月几号,无需加 1 |
| tm_hour | 小时 | 范围是 0~23(24 小时制) |
| tm_min | 分钟 | 范围是 0~59 |
| tm_sec | 秒数 | 范围通常是 0~59 |
| tm_wday | 星期几 | 范围是 0~6(0 代表星期日,1~6 代表星期一至星期六) |
下面我们通过一个示例,看看怎样单独提取这些整数值,并配合字符串数组将 tm_wday 转换为中文星期几。
示例 3:提取年月日与时分秒
#include <chrono>
#include <ctime>
#include <iostream>
#include <string>
int main() {
auto now = std::chrono::system_clock::now();
std::time_t t = std::chrono::system_clock::to_time_t(now);
std::tm* p = std::localtime(&t);
int year = p->tm_year + 1900; // 年份需加 1900
int month = p->tm_mon + 1; // 月份需加 1
int day = p->tm_mday;
int hour = p->tm_hour;
int minute = p->tm_min;
int second = p->tm_sec;
// 0 对应星期日,依此类推
std::string weeks[7] = {
"星期日", "星期一", "星期二", "星期三",
"星期四", "星期五", "星期六"
};
std::string weekday = weeks[p->tm_wday];
std::cout << "日期:" << year << " 年 " << month << " 月 ";
std::cout << day << " 日 " << weekday << '\n';
std::cout << "时间:" << hour << " 时 " << minute << " 分 ";
std::cout << second << " 秒\n";
return 0;
}运行结果如下。
日期:2026 年 10 月 24 日 星期六
时间:15 时 30 分 0 秒分析:
提取年月日时,最关键的两处换算是 p->tm_year + 1900 和 p->tm_mon + 1。这是因为 std::tm 沿用了早期 C 语言的设计:tm_year 记录的是距离 1900 年过去了多少年,比如 2026 年对应的 tm_year 是 126。
而 tm_mon 记录的是从 0 开始的月份下标(0~11),方便直接作为数组下标查询 12 个英文月份名,只有表示几号的 tm_mday 直接就是 1~31。此外,tm_wday 使用 0~6 表示星期几,其中 0 代表 “星期日”,因此我们把 "星期日" 放在 weeks 数组的第 1 项。
平时单独读取年月日时,小伙伴们只要记住一句口诀:“年加 1900,月加 1,几号直接取”。下面这种忘记换算直接赋值的写法就是错误的,会把 2026 年 10 月算成 126 年 9 月。
// 错误方式
int wrongYear = p->tm_year; // 得到 126,而非 2026
int wrongMonth = p->tm_mon; // 10 月会得到 9C++20 直接格式化时间
从 C++20 开始,<chrono> 进一步补齐了日历与时区功能。在完整支持 C++20 标准的新版编译器中引入 <format> 头文件后,我们可以直接调用 std::format(如 std::format("{:%Y-%m-%d}", now))生成日期字符串,省去 std::localtime() 的转换步骤。
不过部分旧版编译器或在线评测环境对 C++20 时区库的支持还不完整。在实际开发中,前面学习的 to_time_t() 配合 std::localtime() 依然是兼容性最好的通用写法。
