写点什么

C++ 软件开发中的时间

作者:行者孙
  • 2021 年 12 月 14 日
  • 本文字数:2075 字

    阅读完需:约 7 分钟

计算机系统中的时间

计算机系统中的时间是一个比较重要的东西。现代社会的各个信息系统,例如电力、交通、金融等各行各业都依赖精确的时间系统,一个时间系统的 bug 很可能造成巨大的经济损失;在普通的开发工作中,也会涉及时间的概念,例如时间戳、日志、性能测试等。因此软件开发人员需要了解一些时间上的概念,包括标准时间、常用的时间和格式等

几种概念的区别和联系

  • GMT 时间:所谓的格林威治时间,历史上曾经作为标准时间

  • UTC 时间:协调世界时,标准的时间,基于原子钟,非常精确,通过不规则地添加闰秒保持与平太阳的时的一致性

  • 本地时间:UTC+时区,例如北京时间就是 UTC+8

  • Posix/Unix 时间:从 UTC 1970 年 1 月 1 日 0 时 0 分起至现在的总秒数,通常叫做时间戳,不考虑闰秒.(如果是 32 位系统,2038 年的某一天将会溢出(秒之后),这就是所谓的 Unix2038 问题)

  • ISO8601:UTC 日期时间格式的国际标准,例如:“2020-12-23T16:53:02.418Z”


北京时间(东八区)与 UTC 时间的时差为 8h, 即 “2020-12-23T16:53:02.418Z”对应的北京时间为"2020-12-24 0:53:02.418",ISO8601 表示为“2020-12-23T16:53:02.418+8:00”


小结:为了国际化,应当采用标准的时间,因此应该使用 UTC 的时间,并且用 ISO8601 的时间日期表示作为持久化格式。

C++中的日期时间

C++ 兼容 C 语言,因此提供的日期时间的概念比较多。主要有 C 语言的日期时间工具和<chrono>。

C 库中的日期时间

  • time_ttime_t 定义在<ctime>中,表示 time since epoch(1970-01-01T00:00::00),精确到秒,因此表示的其实是 Posix 时间。

  • tmtm 定义在<ctime>中,tm 是一个数据结构,保存的是日历时间,年月日时分秒的信息都保存了,并且提供了夏令时的标志位(tm_isdst)。

  • timespectimespec 是 C11 之后引入的数据结构,支持纳秒级别的精度。

  • clock_t. C 语言可以通过 clock() 返回程序启动后的到现在的时钟数(处理器概念中的时钟),可以通过CLOCKS_PER_SEC 来转化为秒数


除了这些类型定义, C 语言还提供了一些时间操作、格式转换的函数,可以参考文档:C date and time utilities 了解更多信息

C++中的 chrono

C++11 之后引入的<chrono>比 C 语言更加强大,主要提供了以下三种主要的类型


  • clock: clock 中定义了诸如 system_clock、steady_clock、high_resolution_clock 乃至 utc_clock(C++20)、gps_clock(C++20)等应用于不同的场景。

  • time_point: time_point 表示某个时刻,例如 system_clock::now()返回的就是当前时刻的时间。

  • duration: 两个时刻的差为 duration。通常用于计算耗时、间隔等场景


具体可以参考文档:chrono

time_point 和 UTC-ISO8601 格式互转

可以把 system_clock 的 time_point 和 UTC-ISO8601 的格式进行相互转换。


以下代码来自Ridge Solutions


#include <chrono>inline std::string to_iso_8601(std::chrono::time_point<std::chrono::system_clock> t) {// convert to time_t which will represent the number of// seconds since the UNIX epoch, UTC 00:00:00 Thursday, 1st. January 1970auto epoch_seconds = std::chrono::system_clock::to_time_t(t); // Format this as date time to seconds resolution// e.g. 2016-08-30T08:18:51std::stringstream stream;stream << std::put_time(gmtime(&epoch_seconds), "%FT%T"); // If we now convert back to a time_point we will get the time truncated// to whole secondsauto truncated = std::chrono::system_clock::from_time_t(epoch_seconds); // Now we subtract this seconds count from the original time to// get the number of extra microseconds..auto delta_us = std::chrono::duration_cast<std::chrono::microseconds>(t - truncated).count(); // And append this to the output stream as fractional seconds// e.g. 2016-08-30T08:18:51.867479stream << "." << std::fixed << std::setw(6) << std::setfill('0') << delta_us; return stream.str();}
复制代码


从 iso_8601 转为 system_clock::time_point,自己实现的:


inline std::chrono::system_clock::time_point utc_from_iso_8601(std::string datetime_in_iso) {  std::tm t = {};  std::istringstream ss(datetime_in_iso);  ss >> std::get_time(&t, "%Y-%m-%dT%H:%M:%SZ");  auto epoch_seconds = std::mktime(&t) - _timezone; // only for Windows  if (-1 == epoch_seconds) return std::chrono::system_clock::time_point();
int y, m, d, h, M; float fraction_second = 0; sscanf(datetime_in_iso.c_str(), "%d-%d-%dT%d:%d:%fZ", &y, &m, &d, &h, &M, &fraction_second); float delta_s = fraction_second - t.tm_sec;
auto truncated = std::chrono::system_clock::from_time_t(epoch_seconds); auto precise_time = truncated + std::chrono::microseconds(int(delta_s * 1000000));
return precise_time;}
复制代码

ref

  1. 时间标准基础知识和ISO8601

  2. C++--UTC时间ISO8601格式与本地时间转换

  3. Format std::time_point in ISO 8601 format with fractional seconds / microseconds in C++

发布于: 1 小时前阅读数: 9
用户头像

行者孙

关注

Nothing replaces hard work 2018.09.17 加入

充满好奇心,终身学习者。 博客:https://01io.tech

评论

发布
暂无评论
C++软件开发中的时间