c/c++中各种时间函数

time_t

time()提供了秒级的精确度
函数time_t time(time_t * timer),返回从TC1970-1-1 0:0:0开始到现在的秒数,
如果需要更高的时间精确度,就需要struct timespec 和 struct timeval来处理

timeval & timespec

  • struct timespec有两个成员,一个是秒,一个是纳秒, 所以最高精确度是纳秒。
    一般由函数int clock_gettime(clockid_t, struct timespec *)获取特定时钟的时间,常用如下4种时钟:
    • CLOCK_REALTIME 统当前时间,从1970年1.1日算起
    • CLOCK_MONOTONIC 系统的启动时间,不能被设置
    • CLOCK_PROCESS_CPUTIME_ID 本进程运行时间
    • CLOCK_THREAD_CPUTIME_ID 本线程运行时间
  • struct timeval有两个成员,一个是秒,一个是微秒, 所以最高精确度是微秒。一般由函数int gettimeofday(struct timeval *tv, struct timezone *tz)获取系统的时间

struct tm

tm的成员包括:tm_sec, tm_mday(day of the month, 注意只有它索引是从1开始), tm_mon等

  • 通过localtime_r(time_t* t, tm* buf)在buf中存储t所对应的时间
  • 通过asctime(tm* tm)可以将其转化为类似Www Mmm dd hh:mm:ss yyyy\n形式的字符串
  • 通过strftime(const char* dest, size_t n, const char* format, tm* tm) 可以将tm转化为和format形式相同的日期格式并储存在dest数组中,最多不能超过n个字节

c++中的chrono库

chrono 库定义三种主要类型以及工具函数和常用 typedef

  • 时钟(clock)
    • system_clock
    • steady_clock
      C++ 标准不提供有关时钟精度、起始点或有效时间范围的保证。通常, std::chrono:system_clock的起点是 1.1.1970,即所谓的UNIX-epoch。对于std::chrono::steady_clock,通常是 PC 的启动时间。
    • 每种clock都有类似的成员函数:
      • rep
      • period
      • std::chrono::duration<rep, period>(见后文)
      • std::chrono::timepoint(见后文)
    • 使用now方法可以获得当前的timepoint
  • 时间点(timepoint)
    • 类模板原型:template <class Clock, class Duration = typename Clock::duration> class time_point;
    • 表示时间中的一个点。它被实现成如同存储一个 Duration 类型的值,指定自 Clock 的纪元起始开始的时间间隔。
    • 使用timepoint的time_since_epoch方法获得离epoch的duration,或者对两个不同的time_point进行加减操作也可以获取duration(当然,也可以获得一个新的timepoint),但不能通过直接输出timepoint来获取duration
  • 时长(duration)
    • template<class rep, class Period = ratio<1> > class duration
      Rep 表示一种数值类型,用来表示Period的数量,比如int float double
      Period是ratio类型,用来表示【用秒表示的时间单位】比如second,milisecond
      template <intmax_t N, intmax_t D = 1> class ratio;
      N代表分子,D代表分母,所以ratio表示一个分数值。
      若 Rep 是浮点类型,则 duration 能表示小数的计次数
    • 有些duration类型可以简写,比如std::chrono::milliseconds = std::chrono::duration</* int45 */, std::milli>
1
2
3
4
5
6
7
8
9
10
11
//一个时间点的类型定义(语法见条款9)
using Time = std::chrono::steady_clock::time_point;

//“enum class”见条款10
enum class Sound { Beep, Siren, Whistle };

//时间段的类型定义
using Duration = std::chrono::steady_clock::duration;

//在时间t,使用s声音响铃时长d
void setAlarm(Time t, Sound s, Duration d);
  • 我们在使用chrono库中的小时,分钟,秒等时间单位时,需要创建如hours(1), seconds(30)来表示时间长度,可以加入using namespace literalsusing namespace chrono_literals以使用标准后缀如秒(s),毫秒(ms)和小时(h)等简化在C++14中的代码,其中标准后缀基于C++11对用户自定义常量的支持。这些后缀在std::literals命名空间中实现,因此上述代码可以按照以下方式重写:1h, 30s

literals标准后缀规定了string和chrono::duration的各种后缀,二者有相同后缀名s,在string中”abcd\0111”s表示使用类型为const char *的”abcd\0111”来构建字符串并且忽略\0作为结束符,同样的,我们可以引入using namespace string_literals来使用s后缀

chrono一些特性

  1. system_clock :: to_time_t(time_point& t)将time_point 转换为 time_t 类型:
    1
    2
    auto const now = std::chrono::system_clock::now();
    std::time_t newt = std::chrono::system_clock::to_time_t(now);

    c++11前获取当前时间 std::time_t oldt = std::time({});

chrono注意事项

  1. 由于各种duration表示不同,chrono库提供了duration_cast类型转换函数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 无精度损失的整数尺度转换:无转型
    std::cout << std::chrono::milliseconds(1s).count() << " 毫秒\n"
    << std::chrono::microseconds(1s).count() << " 微秒\n"
    << std::chrono::nanoseconds(1s).count() << " 纳秒\n";

    // 有精度损失的整数尺度转换:需要转型
    std::cout << std::chrono::duration_cast<std::chrono::minutes>(1s).count()
    << " 分\n";
    const auto t1 = std::chrono::high_resolution_clock::now();
    f();
    const auto t2 = std::chrono::high_resolution_clock::now();
    // 浮点时长不需要转型
    const std::chrono::duration<double, std::milli> fp_ms = t2 - t1;
    // 浮点转整数需要转型
    const auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
  2. system_clock 和 steady_clock对应的duration的period都是纳秒, 也就是10的负9次方,当二者使用now获得的timepoint进行操作时,比如二者相减获取相差时间,输出的duration的单位即为period所对应的单位,比如period为std::micro / std::ratio<1, 1000000>, 则会输出xxx ms,使用duration的count方法会直接输出xxx,没有单位

c/c++中各种时间函数
http://example.com/2023/12/05/chrono用法/
作者
李凯华
发布于
2023年12月5日
许可协议