C++软件开发中的时间
计算机系统中的时间
计算机系统中的时间是一个比较重要的东西。现代社会的各个信息系统,例如电力、交通、金融等各行各业都依赖精确的时间系统,一个时间系统的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语言的日期时间工具和
C库中的日期时间
time_ttime_t 定义在
中,表示 time since epoch(1970-01-01T00:00::00),精确到秒,因此表示的其实是Posix时间。 tmtm 定义在
中,tm是一个数据结构,保存的是日历时间,年月日时分秒的信息都保存了,并且提供了夏令时的标志位(tm_isdst)。 timespectimespec 是C11之后引入的数据结构,支持纳秒级别的精度。
clock_t. C语言可以通过 返回程序启动后的到现在的时钟数(处理器概念中的时钟),可以通过 来转化为秒数
除了这些类型定义, C语言还提供了一些时间操作、格式转换的函数,可以参考 了解更多信息
C++中的chrono
C++11之后引入的比C语言更加强大,主要提供了以下三种主要的类型
: clock中定义了诸如system_clock、steady_clock、high_resolution_clock 乃至utc_clock(C++20)、gps_clock(C++20)等应用于不同的场景。
: time_point 表示某个时刻,例如system_clock::now()返回的就是当前时刻的时间。
: 两个时刻的差为duration。通常用于计算耗时、间隔等场景
time_point 和 UTC-ISO8601格式互转
可以把system_clock的time_point和UTC-ISO8601的格式进行相互转换。
#include
inline std::string to_iso_8601(std::chrono::time_point t) {
// convert to time_t which will represent the number of
// seconds since the UNIX epoch, UTC 00:00:00 Thursday, 1st. January 1970
auto epoch_seconds = std::chrono::system_clock::to_time_t(t);
// Format this as date time to seconds resolution
// e.g. 2016-08-30T08:18:51
std::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 seconds
auto 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(t - truncated).count();
// And append this to the output stream as fractional seconds
// e.g. 2016-08-30T08:18:51.867479
stream << "." << 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;
}