文章目录
C++提供日期和时间相关的实现,分为C风格和C++风格。
- C风格的提供了获取当前墙上时间,时间转文本格式,文本格式转时间格式
- C++风格提供了duration模板用于各种精度的转换,system_clock获取墙上时间(可转C风格时间),steady_clock获取单调递增时间
ctime
C 风格日期和时间函数,函数声明如下:
namespace std {
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
long int tm_gmtoff;
const char* tm_zone;
};
std::time_t time( std::time_t* arg );
std::tm* localtime( const std::time_t *time );
struct tm* gmtime (const time_t * timer);
char* asctime( const std::tm* time_ptr );
char* ctime( const std::time_t* time );
std::size_t strftime( char* str, std::size_t count, const char* format, const std::tm* time );
std::clock_t clock();
} // end namespace std
std::time
获取当前日历时间(从纪元起经历的秒),如果arg
不是空指针并将它存储于arg
所指向的对象,错误时为 -1 。std::time_t
一般来说是一个in32_t类型,所以时间会在2038年出错。
std::localtime
把当前的日历时间(从纪元起经历的秒)转换为本地时间表达的日历时间std::tm
。
- 例子
#include <sstream>
#include <iostream>
const std::string LocalTime(char data_split = '/', char time_split = ':')
{
std::time_t t = std::time(nullptr);
std::tm* tm = std::localtime(&t);
int sec = tm->tm_sec, min = tm->tm_min, hour = tm->tm_hour;
int day = tm->tm_mday, mon = 1 + tm->tm_mon, year = 1900 + tm->tm_year;
delete tm;
std::ostringstream ss;
ss << year << data_split;
if (mon < 9) { ss << "0"; }
ss << mon << data_split;
if (day < 9) { ss << "0"; }
ss << day << data_split;
if (hour < 9) { ss << "0"; }
ss << hour << time_split;
if (min < 9) { ss << "0"; }
ss << min << time_split;
if (sec < 9) { ss << "0"; }
ss << sec;
return ss.str();
}
int main(int argc, char *argv[])
{
std::cout << LocalTime() << std::endl;
return 0;
}
- 输出
2021/05/17/15:41:05
std::gmtime
把当前的日历时间转换为表达式为std::tm
的GMT日历时间。
std::string RFC1123GMTDate()
{
// https://datatracker.ietf.org/doc/html/rfc1123#5.2.14
const char* const kWday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const char* const kMMon[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
std::time_t t = std::time(nullptr);
std::tm* tm = std::gmtime(&t);
char buf[256] = {0};
// Thu, 31 May 2007 20:35:00 GMT
int32_t len = snprintf(buf, 256, "%s, %02d %s %d %02d:%02d:%02d GMT", kWday[tm->tm_wday], tm->tm_mday, kMMon[tm->tm_mon],
tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
return std::string(buf, len); // Wed, 26 May 2021 12:11:35 GMT
}
std::asctime
转换给定日历时间std::tm
为拥有下列固定 25 字符形式的文本表示: Www Mmm dd hh:mm:ss yyyy\n
- Www :星期之日的三字母英文缩写,来自
time_ptr->tm_wday
,为 Mon 、 Tue 、 Wed 、 Thu 、 Fri 、 Sat 、 Sun 之一。 - Mmm :月名的三字母英文缩写,来自
time_ptr->tm_mon
,为 Jan 、 Feb 、 Mar 、 Apr 、 May 、 Jun 、 Jul 、 Aug 、 Sep 、 Oct 、 Nov 、 Dec 之一。 - dd :2 位数月之日 ,来自
timeptr->tm_mday
,如同 sprintf 用 %2d 打印 - hh :2 位小时,来自
timeptr->tm_hour
,如同 sprintf 用 %.2d 打印 - mm :2 位分,来自
timeptr->tm_min
,如同 sprintf 用 %.2d 打印 - ss :2 位秒,来自
timeptr->tm_sec
,如同 sprintf 用 %.2d 打印 - yyyy :4 位年,来自
timeptr->tm_year + 1900
,如同 sprintf 用 %4d 打印
例子
#include <ctime>
#include <iostream>
int main()
{
std::time_t result = std::time(NULL);
std::cout << std::asctime(std::localtime(&result));
}
输出
Tue May 11 18:32:27 2021
std::ctime
转换给定的从纪元起时间为日历时间,再转换为文本表示,如同通过调用std::asctime(std::localtime(time))
。
std::strftime
std::ctime的逆向操作,根据给定的时间字符串转换为std::time_t时间,阅读官方文档按照它的格式写就好了。
chrono
std::ratio
一个有理数模块,此模板的每个实例化都准确表示任一确定有理数。另外,分母Denom
不可为零且不可等于最负的值。需要约分分子和分母到最简。
namespace std {
template <std::intmax_t Num, std::intmax_t Denom = 1> class ratio
{
public:
static constexpr intmax_t num;
static constexpr intmax_t den;
typedef ratio<num, den> type;
}
typedef ratio<1LL, 1000000000000000000LL> atto;
typedef ratio<1LL, 1000000000000000LL> femto;
typedef ratio<1LL, 1000000000000LL> pico;
typedef ratio<1LL, 1000000000LL> nano;
typedef ratio<1LL, 1000000LL> micro;
typedef ratio<1LL, 1000LL> milli;
typedef ratio<1LL, 100LL> centi;
typedef ratio<1LL, 10LL> deci;
typedef ratio< 10LL, 1LL> deca;
typedef ratio< 100LL, 1LL> hecto;
typedef ratio< 1000LL, 1LL> kilo;
typedef ratio< 1000000LL, 1LL> mega;
typedef ratio< 1000000000LL, 1LL> giga;
typedef ratio< 1000000000000LL, 1LL> tera;
typedef ratio< 1000000000000000LL, 1LL> peta;
typedef ratio<1000000000000000000LL, 1LL> exa;
} // end namespace std
std::chrono::duration
表示时间间隔(秒)。它由Rep类型的计次数和Period类型的计次周期组成,其中计次周期是一个编译期有理数常量,表示从一个计次到下一个的秒数。
namespace chrono {
template <class Rep, class Period = std::ratio<1>>
class duration {
public:
typedef Rep rep;
constexpr rep count() const;
};
typedef duration<long long, nano> nanoseconds;
typedef duration<long long, micro> microseconds;
typedef duration<long long, milli> milliseconds;
typedef duration<long long > seconds;
typedef duration< long, ratio< 60> > minutes;
typedef duration< long, ratio<3600> > hours;
} // end namespace chrono
- 例子
#include <chrono>
#include <iostream>
int main(int argc, char *argv[])
{
auto deca_sec = std::chrono::seconds(10);
// deca_sec.count() * deca_sec.num / deca_sec.den * microseconds.den / microseconds.num
std::cout << std::chrono::microseconds(deca_sec).count() << std::endl; // 10000000
// deca_sec.count() * deca_sec.num / deca_sec.den * milliseconds.den / milliseconds.num
std::cout << std::chrono::milliseconds(deca_sec).count() << std::endl; // 10000
std::cout << std::chrono::duration<float, std::ratio<60, 1>>(deca_sec).count() << std::endl; // 0.166667
std::cout << std::chrono::duration<float, std::ratio<16, 1>>(deca_sec * 10).count() << std::endl; // 6.25
return 0;
}
std::chrono::duration_cast
转换std::chrono::duration为不同类型ToDuration的时长
template <class ToDuration, class Rep, class Period>
constexpr ToDuration duration_cast(const duration<Rep, Period>& fd);
std::chrono::time_point
表示时间中的一个点。单独的一个time_point是没有任何意义的,它需要跟同类型的time_point进行-
或者+
操作才能得到一个有意义的std::chrono::duration对象。
namespace chrono {
template <class Clock, class Duration = typename Clock::duration>
class time_point
{
public:
typedef Clock clock;
typedef Duration duration;
typedef typename duration::rep rep;
typedef typename duration::period period;
};
} // end namespace chrono
std::chrono::system_clock
表示系统范围的实时壁钟。它可以不单调:大多数系统上,系统时间可以在任何时候被调节。它是唯一有能力映射其时间点到C风格时间的C++时钟。因为是墙上时间所以多了to_time_t
和from_time_t
两个接口。
namespace chrono {
class system_clock
{
public:
typedef microseconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef chrono::time_point<system_clock> time_point;
static const bool is_steady = false; // constexpr in C++14
static time_point now() noexcept;
static time_t to_time_t (const time_point& __t) noexcept;
static time_point from_time_t(time_t __t) noexcept;
};
} // end namespace chrono
- 例子
#include <chrono>
#include <thread>
#include <iostream>
int main(int argc, char *argv[])
{
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - now).count() << std::endl; // 可能输出 21
std::time_t t = std::chrono::system_clock::to_time_t(now);
std::cout << std::ctime(&t) << std::endl; // Wed May 12 23:42:05 2021
return 0;
}
std::chrono::steady_clock
表示单调时钟。此时钟的时间点无法减少,因为物理时间向前移动。此时钟与壁钟时间无关(例如,它能是上次重启开始的时间),且最适于度量间隔。
namespace chrono {
class steady_clock
{
public:
typedef nanoseconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef chrono::time_point<steady_clock, duration> time_point;
static const bool is_steady = true; // constexpr in C++14
static time_point now() noexcept;
};
} // end namespace chrono