C++ 时间和日期


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_tfrom_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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值