一、介绍
在C的ctime库中包含了一些对日期和时间相关的类型和函数,可以方便我们处理对于相关的逻辑。
基本的类型有三个:
clock_t
:用于保存短时间间隔(可能几分钟)的算数类型time_t
:用于保存长时间间隔(可能几个世纪)的算数类型tm
:一个结构体,用于保存日期和时间(自1900年起计算)
其中tm
的结构定义如下:
struct tm
{
int tm_sec; // seconds after the minute - [0, 60] including leap second //一分钟的第几秒,从0开始计数
int tm_min; // minutes after the hour - [0, 59] //一小时的第几分种,从0开始计数
int tm_hour; // hours since midnight - [0, 23] //一天的第几个小时,从0开始计数
int tm_mday; // day of the month - [1, 31] //一个月的第几天,从1开始计数
int tm_mon; // months since January - [0, 11] //一年的第几个月,从0开始计数,即0代表1月,1代表2月
int tm_year; // years since 1900 //从1900年到现在经过的年份
int tm_wday; // days since Sunday - [0, 6] //一个星期的第几天,从0开始计数,即0代表星期一,依次类推
int tm_yday; // days since January 1 - [0, 365] //一年的第几天,从0计数,0代表第一天,依次类推
int tm_isdst; // daylight savings time flag //夏令时标志
};
前面的英文为原有注释,后面的中文为我的翻译,可以对照着看。
除此之外,还有一系列函数:
函数 | 说明 |
---|---|
t=clock() | t为程序开始运行到现在所经历的时钟滴答数;t是clock_t 类型 |
t=time(pt) | 获取1900年到现在经过的秒数,pt可以为nullptr |
d=difftime(t2,t1) | d表示t2-t1 的秒数 |
ptm=localtime(pt) | 将pt转换为本地时间ptm,为tm结构 |
ptm=gmtime(pt) | 若pt==nullptr ,则ptm=nullptr ;否则ptm指向*pt对应的格林威治标准时间(Greenwich Mean Time,GTM)tm |
t=mktime(ptm) | *ptm 对应的time_t 或time_t (-1) |
p=asctime(ptm) | p是*ptm 的C风格字符串表示 |
p=ctime(t) | p=asctime(localtime(t)) |
n=strftime(p,max,fmt,ptm) | 格式化ptm,格式由格式字符串fmt控制,由p缓存区接收,max为p的大小 |
二、简单使用
上面的函数比较多,但实际上我们平时用的并不多,比如最常见的一个用途就是得到当前的时间、并以一定的格式进行输出,那么就可以这样写:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<ctime>
using namespace std;
int main()
{
time_t t=time(nullptr);
tm* pt=localtime(&t);
char buf[255]{};
strftime(buf,255,"%F %T", pt);
cout << buf;
}
这里使用的time
函数传入nullptr
,即可获取到自1900年到现在所经过的秒数,存放在了t
中。
然后接下来,使用localtime
函数将其转换为前面提到的tm
结构,正如该函数名所言,此时它将被转换为本地时间。
此时你完成可以用前面提到的tm结构一个一个进行解析出年月份,但那样有些太麻烦了,所以这里我使用了strftime
函数来格式化时间。
它的第一个参数为接收格式化结果的缓存区,第二个参数为缓存区大小,第三个参数为格式控制符,第四个参数就是前面获取到的本地时间tm
结构。
这里的日期格式控制符非常多,这里我只用了%F
与%T
,前者代表年月日,后者代表时分秒。
运行结果为:
这两个格式化可以稍微记一下,毕竟比较常用。
如果你希望对其进行更加精确的控制,那么可以看下面的内容。
三、格式化符号
注意,下面这些格式化符号并不是该函数独有的,其它语言、库基本也都是参照的该规范,所以只要是需要填入格式化符号的,下面这些符号基本就是通用的:
%a
:星期名缩写%A
:完整星期名%b
:月份名缩写%B
:完整月份名%c
:日期和时间表示%C
:年份除以100,截取为[00:99]间的十进制整数%d
:月内第几天,[01:31]间的十进制整数%D
:等价于%m%d%y%e
:月内第几天,[01:31]间的十进制整数,如果是一位数字,前面补一个空格%F
:等价于%Y-%m-%d;IS08601日期格式%g
:按周记的年份十进制值的后两位数字,[00:99]%G
:按周记的年份十进制值(如2012)》%h
:等价于%b%H
:(24小时制)小时值十进制表示,[00:23]%1
:(12小时制)小时值十进制表示,[01:12]%j
:年内第几天的十进制值,[001:366)%m
:月份十进制值,[01:12]%M
:分钟十进制值,[00:59]%n
:换行符%p
:十二小时制上午/下午的区域表示%r
:十二小时制时间%R
:等价于%H:%M%S
:秒十进制值,[00:60]%t
:水平制表符%T
:等价于%H:%M:%S;IS08601时间格式%u
:IS08601星期十进制值,[1:7];星期一为1%U
:年内第几个星期(第一个星期天为第1周的第一天)的十进制表示,[00:53]%V
:IS08601星期值的十进制表示,[01:53]%W
:星期几的十进制表示,[0:6];星期天为0%W
:年内第几个星期(第一个星期一为第1周的第一天)的十进制表示,[00:53]%x
:日期的恰当区域表示%X
:时间的恰当区域表示%y
:年份十进制表示的后两位数字,[00:99]%Y
:年份十进制表示(如2012)%z
:与世界标准时间(UTC)的偏移,用IS08601格式表示,如-0430(落后UTC,也就是格林威治时间 4.5小时):如不能确定时区则没有任何结果%Z
:时区名区域表示或缩写;如不能确定时区则没有任何结果%%
:字符%
四、chrono时间库
C++11 引入了一个新的日期和时间库 chrono
,提供了更精确和更灵活的时间操作。chrono
不仅支持秒、毫秒等时间单位,还支持基于时间点的计算。
常用类型:
-
std::chrono::system_clock
:表示系统时钟,可以获取当前时间和时间点。 -
std::chrono::steady_clock
:用于测量程序运行时间的稳定时钟。它是单调递增的,不受系统时间修改的影响。 -
std::chrono::high_resolution_clock
:提供最高精度的时钟,通常是steady_clock
的一种实现。
比如使用该库获取当前时间的代码为:
#define _CRT_SECURE_NO_WARNINGS
#include <chrono>
#include <iomanip>
#include <iostream>
int main() {
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
std::cout << "Current time: " << std::put_time(std::localtime(&now_time), "%F %T") << std::endl;
return 0;
}
但其更常用的地方在于,用来计算程序的执行时间。
#include<chrono>
#include<iostream>
using namespace std;
int main() {
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000; i++) {
cout << i << endl;
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = end - start;
std::cout << "Elapsed time: " << duration.count() << " seconds\n";
return 0;
}
通过上面这种方式,我们可以高精度的计算一段代码执行所需要花费的时间: