C/C++时间函数详解及使用场景
一、基本概念
C/C++中处理时间主要有两种方式:
- C-style时间函数(定义在
<time.h>
或<ctime>
中) - C++11引入的
<chrono>
库(更现代的时间处理方式)
二、C-style时间函数
1. 核心数据类型
time_t
:通常为long类型,表示从1970年1月1日00:00:00(UNIX纪元)到当前时刻的秒数struct tm
:包含年月日时分秒等字段的结构体clock_t
:用于测量处理器时间的类型
2. 常用函数及示例
(1) 获取当前时间
#include <time.h>
#include <stdio.h>int main() {time_t now;time(&now); // 获取当前时间printf("当前时间戳: %ld\n", now);return 0;
}
(2) 时间转换
struct tm *local_time = localtime(&now); // 转换为本地时间
printf("%d年%d月%d日 %d:%d:%d\n", local_time->tm_year + 1900,local_time->tm_mon + 1,local_time->tm_mday,local_time->tm_hour,local_time->tm_min,local_time->tm_sec);
(3) 时间格式化
#include <time.h>
#include<stdio.h>
#include<string.h>
#include <pthread.h>
#include <stdbool.h>
#include<sys/time.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
bool getTimStrS(char* data,const int iLen)
{ char buffer[64];memset(buffer, 0, sizeof(buffer));struct timeval tv;struct tm tm;size_t len = 28;memset(&tv, 0, sizeof(tv));memset(&tm, 0, sizeof(tm));gettimeofday(&tv, NULL);localtime_r(&tv.tv_sec, &tm);strftime(buffer, 64, "%Y-%m-%d %H:%M:%S", &tm);if(data&&iLen>sizeof(buffer)){ strcpy(data,buffer);return true; }return false;
}//带毫秒
bool getTimStrMs(char* data,const int iLen)
{char buf[32] = {0};struct timeval tv;struct tm tm;size_t len = 28;memset(&tv, 0, sizeof(tv));memset(&tm, 0, sizeof(tm));gettimeofday(&tv, NULL);localtime_r(&tv.tv_sec, &tm);strftime(buf, len, "%Y-%m-%d %H:%M:%S", &tm);len = strlen(buf);snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%03ld", tv.tv_usec / 1000);if (data && iLen > strlen(buf)) {strncpy(data, buf, iLen - 1);data[iLen - 1] = '\0';return true;}return false;
}
(4) 计算时间差秒
time_t start, end;
time(&start);
// 执行一些操作...
time(&end);
double diff = difftime(end, start); // 计算时间差(秒)
printf("耗时: %.2f秒\n", diff);
(5)计算时间差(毫秒)
#include <sys/time.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
// 使用更明确的类型定义
typedef uint64_t DDWORD;
DDWORD getMsClick();
DDWORD getMsClickEnd(DDWORD timeRecord);
// 获取当前毫秒时间戳
inline DDWORD getMsClick() {struct timeval tv;if (gettimeofday(&tv, NULL) == -1) {fprintf(stderr,"gettimeofday failed\n");return -1;}return (DDWORD)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}// 计算耗时
inline DDWORD getMsClickEnd(DDWORD timeRecord) {return getMsClick() - timeRecord;
}int main()
{DDWORD start = getMsClick();sleep(2);start = getMsClickEnd(start);fprintf(stdout,"spend MS =%ld\n",start);return 0;
}
(6)计算时间差微秒
inline DDWORD getUsClick() {struct timeval tv;if (gettimeofday(&tv, NULL) == -1) {fprintf(stderr,"gettimeofday failed\n");return -1;}return (DDWORD)tv.tv_sec * 1000000 + tv.tv_usec;
}
3. 适用场景
linxu c
三、C++11 chrono库
1. 核心组件
std::chrono::duration
:表示时间间隔std::chrono::time_point
:表示时间点std::chrono::system_clock
:系统范围的实时时钟std::chrono::steady_clock
:单调时钟,适合测量时间间隔
1. std::chrono::duration(时间间隔)
模板类std::chrono::duration<Rep, Period>表示两个时间点之间的时间间隔,由计数值(Rep类型)和单位周期(Period,编译期有理数常量)组成。
std::chrono::duration<int> sec(3); // 3秒
std::chrono::duration<long, std::milli> ms(500); // 500毫秒
特性
支持算术运算(如+、-、*)和比较操作。
提供预定义类型:nanoseconds、microseconds、milliseconds、seconds等。
可通过count()获取内部计数值,duration_cast转换单位。
2. std::chrono::time_point(时间点)
模板类std::chrono::time_point<Clock, Duration>表示特定时钟下的时间点,由Clock类型和uration类型共同决定。
auto now = std::chrono::system_clock::now(); // 获取当前系统时间点
操作
支持与duration的加减运算(如time_point + duration = time_point)。
可计算两个时间点的差值(返回duration)。
提供time_since_epoch()获取从时钟纪元开始的时长。
3. std::chrono::system_clock(系统时钟)
表示系统范围的实时时钟,与日历时间相关。
时间可能因系统时间调整(如NTP同步)而回退或跳跃。
提供to_time_t()和from_time_t()与C风格时间转换。
用途
适合记录日志时间、文件修改时间等需要与实际时间对应的场景。
4. std::chrono::steady_clock(单调时钟)
保证单调递增,不受系统时间调整影响。
适用于测量时间间隔(如性能分析)。
时钟纪元(epoch)通常为程序启动时间。
auto start = std::chrono::steady_clock::now();
// 执行操作...
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
对比总结
组件 | 关键特性 | 典型应用场景 |
---|---|---|
duration | 时间间隔,支持单位转换和运算 | 超时控制、耗时统计 |
time_point | 特定时钟下的时间点 | 事件时间戳记录 |
system_clock | 实时时钟,可能非单调 | 日志记录、日历时间相关操作 |
steady_clock | 单调递增,稳定计时 | 性能分析、基准测试 |
2. 常用操作及示例
(1) 获取当前时间
#include <chrono>
#include <iostream>auto now = std::chrono::system_clock::now();
auto now_time = std::chrono::system_clock::to_time_t(now);
std::cout << "当前时间: " << ctime(&now_time);
(2) 高精度计时
auto start = std::chrono::high_resolution_clock::now();
// 执行一些操作...
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "耗时: " << duration.count() << "毫秒\n";
(3)封装时间计时
class HighPrecisionTimer {
public:using Clock = std::chrono::high_resolution_clock;using TimePoint = std::chrono::time_point<Clock>;using Duration = std::chrono::nanoseconds;// 启动计时器void start() {try {start_time = Clock::now();} catch (const std::exception& e) {std::cerr << "Timer start error: " << e.what() << std::endl;throw;}}// 获取经过的时间(返回指定单位的计数值)template<typename T = std::chrono::milliseconds>auto elapsed() const {if (!is_running()) {throw std::logic_error("Timer not started");}return std::chrono::duration_cast<T>(Clock::now() - start_time).count();}// 获取经过的时间(返回duration对象)template<typename T = std::chrono::milliseconds>T elapsed_duration() const {if (!is_running()) {throw std::logic_error("Timer not started");}return std::chrono::duration_cast<T>(Clock::now() - start_time);}// 获取当前时间戳(毫秒)static int64_t currentTimestamp() noexcept {return std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now().time_since_epoch()).count();}// 检查计时器是否已启动bool is_running() const noexcept {return start_time != TimePoint{};}// 重置计时器void reset() noexcept {start_time = TimePoint{};}// 获取并重置计时器(返回之前的时间)template<typename T = std::chrono::milliseconds>auto lap() {auto duration = elapsed<T>();start();return duration;}private:TimePoint start_time{};
};// 支持RAII自动计时的作用域计时器
class ScopedTimer {
public:explicit ScopedTimer(std::string tag, bool auto_log = true) : tag(std::move(tag)), auto_log(auto_log) {timer.start();}~ScopedTimer() {if (auto_log) {auto us = timer.elapsed<std::chrono::microseconds>();std::cout << tag << " elapsed: " << formatDuration(us) << "\n";}}// 获取当前耗时template<typename T = std::chrono::milliseconds>auto elapsed() const {return timer.elapsed<T>();}// 手动记录时间点void log(const std::string& message = "") {auto us = timer.elapsed<std::chrono::microseconds>();std::cout << tag << " [" << message << "] elapsed: " << formatDuration(us) << "\n";}private:std::string tag;HighPrecisionTimer timer;bool auto_log;// 智能格式化时间显示static std::string formatDuration(int64_t microseconds) {static const char* units[] = {"μs", "ms", "s"};static const int64_t thresholds[] = {1000, 1000};double value = microseconds;int unit_index = 0;while (unit_index < 2 && value >= thresholds[unit_index]) {value /= thresholds[unit_index];unit_index++;}std::ostringstream oss;oss << std::fixed << std::setprecision(unit_index > 0 ? 3 : 0) << value << units[unit_index];return oss.str();}
};// 线程安全的时间戳生成器
class TimestampGenerator {
public:static std::string getTimestamp(bool with_milliseconds = true) {std::lock_guard<std::mutex> lock(mutex);auto now = std::chrono::system_clock::now();auto time = std::chrono::system_clock::to_time_t(now);std::tm tm;localtime_r(&time, &tm);std::ostringstream oss;oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");if (with_milliseconds) {auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() % 1000;oss << "." << std::setfill('0') << std::setw(3) << ms;}return oss.str();}private:static std::mutex mutex;
};std::mutex TimestampGenerator::mutex;
void exampleUsage() {// 基本计时器使用HighPrecisionTimer timer;timer.start();// 执行一些操作...auto elapsed_ms = timer.elapsed(); // 默认毫秒auto elapsed_ns = timer.elapsed<std::chrono::nanoseconds>();std::cout << "Operation took " << elapsed_ms << "ms (" << elapsed_ns << "ns)\n";// 作用域计时器{ScopedTimer timer("Database query");// 执行数据库查询...} // 自动输出耗时// 带手动记录的作用域计时器{ScopedTimer timer("Complex operation", false);// 第一步操作...timer.log("Step 1 completed");// 第二步操作...timer.log("Step 2 completed");}// 获取时间戳std::cout << "Current timestamp: " << TimestampGenerator::getTimestamp() << "\n";std::cout << "Current time (no ms): " << TimestampGenerator::getTimestamp(false) << "\n";
}
(4)时间打印
#include <chrono>
#include <format>
#include <stdexcept>
#include <string>namespace timestamp_utils {// 预定义格式constexpr auto kSecFormat = "{:%Y-%m-%d %H:%M:%S}";// 获取北京时间时区(UTC+8)inline const std::chrono::time_zone* get_beijing_timezone() {try {return std::chrono::locate_zone("Asia/Shanghai"); // 或 "Etc/GMT-8"} catch (...) {return std::chrono::locate_zone("UTC"); // 回退方案}}// 安全格式化模板(带时区转换)template<typename Duration>std::string format_safe(std::chrono::system_clock::time_point tp) {try {const auto* tz = get_beijing_timezone();auto local_time = std::chrono::zoned_time(tz, tp);if constexpr (std::is_same_v<Duration, std::chrono::milliseconds>) {auto sec = std::chrono::floor<std::chrono::seconds>(tp);auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(tp - sec);return std::format("{}.{:03d}", std::chrono::floor<std::chrono::seconds>(local_time.get_local_time()),ms.count());} else {return std::format(kSecFormat, std::chrono::floor<Duration>(local_time.get_local_time()));}} catch (...) {return std::format(kSecFormat, std::chrono::zoned_time(get_beijing_timezone(), std::chrono::system_clock::now()).get_local_time());}}// 获取当前北京时间(秒级)std::string get_timestamp() {return format_safe<std::chrono::seconds>(std::chrono::system_clock::now());}// 获取当前北京时间(毫秒级)std::string get_timestamp_with_millis() {return format_safe<std::chrono::milliseconds>(std::chrono::system_clock::now());}
}void test()
{std::cout << "Current time: " << timestamp_utils ::get_timestamp() << "\n";std::cout << "Current time with millis: " << timestamp_utils ::get_timestamp_with_millis() << "\n";
}
3. 适用场景
- 需要高精度计时(毫秒、微秒、纳秒级)
- 复杂的日期时间计算
- C++11及以上环境
四、Windows平台特有函数
1. GetTickCount()
#include <windows.h>DWORD start = GetTickCount();
// 执行一些操作...
DWORD end = GetTickCount();
printf("耗时: %d毫秒\n", end - start);
2. 适用场景
- Windows平台专用程序
- 需要毫秒级精度但不需纳秒级的场景
五、MFC时间类(CTime和CTimeSpan)
CTime time = CTime::GetCurrentTime();
CString str = time.Format("%Y-%m-%d %H:%M:%S");
CTimeSpan span(0, 1, 30, 0); // 1小时30分钟
CTime newTime = time + span;
适用场景:MFC应用程序开发6
六、异同对比
特性 | C-style时间函数 | C++ chrono | Windows API | MFC类 |
---|---|---|---|---|
精度 | 秒级 | 纳秒级 | 毫秒级 | 秒级 |
跨平台 | 是 | C++11及以上 | 仅Windows | 仅Windows |
复杂度 | 简单 | 中等 | 简单 | 简单 |
主要用途 | 基本日期时间操作 | 高精度计时 | Windows计时 | MFC应用 |
七、使用建议
- 简单日期时间操作:优先使用C-style函数,兼容性好
- 高精度计时:使用C++ chrono库
- Windows平台:考虑GetTickCount()等API
- MFC开发:使用CTime和CTimeSpan类
- 跨平台高精度:C++ chrono是最佳选择
八、延时函数
1. 标准库方法(推荐,跨平台)
-
std::this_thread::sleep_for
需包含<chrono>
和<thread>
头文件,支持纳秒级精度:#include <chrono> #include <thread> void delay(int ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); } // 使用示例:delay(3000); // 延时3秒
2. 传统 C 库方法
-
sleep
/usleep
sleep
(秒级)和usleep
(微秒级)需包含<unistd.h>
(Linux)或<windows.h>
(Windows):#include <ctime> void delay_sec(int sec) {time_t start = time(nullptr);while (time(nullptr) - start < sec); }
- Windows 下等效函数为
Sleep
(毫秒级,首字母大写):#include <windows.h> Sleep(3000); // 延时3秒
3. 手动实现延时(不依赖库)
- 基于
clock()
使用<ctime>
头文件,适合简单场景但精度有限:#include <ctime> void delay_ms(int ms) {clock_t end = clock() + (ms * CLOCKS_PER_SEC / 1000);while (clock() < end); }
- 基于
time()
秒级延时,适用于对精度要求不高的场景:#include <ctime> void delay_sec(int sec) {time_t start = time(nullptr);while (time(nullptr) - start < sec); }
4. 注意事项
- 跨平台兼容性
std::this_thread::sleep_for
是 C++11 标准,兼容性最佳;sleep
/usleep
需区分系统。 - 精度差异
clock()
依赖 CPU 时钟频率,time()
精度通常为秒级,而std::chrono
支持更高精度。 - 阻塞线程
所有延时函数均会阻塞当前线程,若需非阻塞延时需结合异步编程。
总结建议
场景 | 推荐方法 | 头文件 |
---|---|---|
高精度跨平台 | std::this_thread::sleep_for | <chrono> , <thread> |
Linux 系统 | sleep / usleep | <unistd.h> |
Windows 系统 | Sleep | <windows.h> |
无库依赖简单实现 | clock() 或 time() 循环 | <ctime> |