27.C/C++ 日期与时间库详解:ctime 与 chrono 的用法及实例

一、介绍

在C的ctime库中包含了一些对日期和时间相关的类型和函数,可以方便我们处理对于相关的逻辑。

基本的类型有三个:

  1. clock_t:用于保存短时间间隔(可能几分钟)的算数类型
  2. time_t:用于保存长时间间隔(可能几个世纪)的算数类型
  3. 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_ttime_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,前者代表年月日,后者代表时分秒。

运行结果为:

image-20231222215611947

这两个格式化可以稍微记一下,毕竟比较常用。

如果你希望对其进行更加精确的控制,那么可以看下面的内容。

三、格式化符号

注意,下面这些格式化符号并不是该函数独有的,其它语言、库基本也都是参照的该规范,所以只要是需要填入格式化符号的,下面这些符号基本就是通用的:

  • %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;
}

通过上面这种方式,我们可以高精度的计算一段代码执行所需要花费的时间:

image.png

作者:余识
全部文章:0
会员文章:0
总阅读量:0
c/c++pythonrustJavaScriptwindowslinux