从 C++ 中的 std::chrono::time_point 中提取年/月/日等

Posted

技术标签:

【中文标题】从 C++ 中的 std::chrono::time_point 中提取年/月/日等【英文标题】:Extract year/month/day etc. from std::chrono::time_point in C++ 【发布时间】:2013-04-04 04:20:13 【问题描述】:

如何从std::chrono::time_point 对象中提取年、月、日、小时、分钟、秒和毫秒

我只看到了如何提取例如总量的示例。 duration 的秒数。

【问题讨论】:

How to convert std::chrono::time_point to calendar datetime string with fractional seconds?的可能重复 【参考方案1】:

您只能从system_clock::time_point 中提取此信息。这是系统提供的唯一与民用日历相关的时钟。以下是使用此时钟获取当前时间点的方法:

 system_clock::time_point now = system_clock::now();

然后您可以将其转换为time_t

time_t tt = system_clock::to_time_t(now);

然后,您可以使用 C 库将 time_t 转换为 tm,但您必须选择是希望在 UTC 时区还是本地时区进行转换:

tm utc_tm = *gmtime(&tt);
tm local_tm = *localtime(&tt);

然后就可以打印出tm的组成部分了,例如:

std::cout << local_tm.tm_year + 1900 << '\n';
std::cout << local_tm.tm_mon + 1 << '\n';
std::cout << local_tm.tm_mday << '\n';

另外

如果您愿意,您可以利用这些非保证信息:

我所知道的system_clock 的每个实现都基于unix time。 IE。自 1970 UTC 新年以来的秒数,忽略闰秒。而且这个计数的精度通常比秒还好。这是一个提取所有这些信息的完整程序:

#include <chrono>
#include <ctime>
#include <iostream>

int
main()

    using namespace std;
    using namespace std::chrono;
    typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;
    system_clock::time_point now = system_clock::now();
    system_clock::duration tp = now.time_since_epoch();
    days d = duration_cast<days>(tp);
    tp -= d;
    hours h = duration_cast<hours>(tp);
    tp -= h;
    minutes m = duration_cast<minutes>(tp);
    tp -= m;
    seconds s = duration_cast<seconds>(tp);
    tp -= s;
    std::cout << d.count() << "d " << h.count() << ':'
              << m.count() << ':' << s.count();
    std::cout << " " << tp.count() << "["
              << system_clock::duration::period::num << '/'
              << system_clock::duration::period::den << "]\n";

    time_t tt = system_clock::to_time_t(now);
    tm utc_tm = *gmtime(&tt);
    tm local_tm = *localtime(&tt);
    std::cout << utc_tm.tm_year + 1900 << '-';
    std::cout << utc_tm.tm_mon + 1 << '-';
    std::cout << utc_tm.tm_mday << ' ';
    std::cout << utc_tm.tm_hour << ':';
    std::cout << utc_tm.tm_min << ':';
    std::cout << utc_tm.tm_sec << '\n';

创建自定义duration 来模拟天很方便:

typedef duration<int, ratio_multiply<hours::period, ratio<24> >::type> days;

现在您可以通过以下方式获取自纪元以来的时间,尽可能精确地进行:

system_clock::duration tp = now.time_since_epoch();

然后将其截断为天,然后减去。

然后将其截断为小时,然后减去。

继续直到你减去秒数。

剩下的就是以system_clock::duration 为单位的几分之一秒。因此,如图所示打印出该运行时间值和该值的编译时间单位。

对我来说,这个程序打印出来:

15806d 20:31:14 598155[1/1000000]
2013-4-11 20:31:14

我的输出表明system_clock::duration 精度为微秒。如果需要,可以将其截断为毫秒:

milliseconds ms = duration_cast<milliseconds>(tp);

更新

This header-only C++11/14 library 封装了上面的工作,将客户端工作减少到:

#include "date.h"
#include <iostream>

int
main()

    // Reduce verbosity but let you know what is in what namespace
    namespace C = std::chrono;
    namespace D = date;
    namespace S = std;

    auto tp = C::system_clock::now(); // tp is a C::system_clock::time_point
    
        // Need to reach into namespace date for this streaming operator
        using namespace date;
        S::cout << tp << '\n';
    
    auto dp = D::floor<D::days>(tp);  // dp is a sys_days, which is a
                                      // type alias for a C::time_point
    auto ymd = D::year_month_daydp;
    auto time = D::make_time(C::duration_cast<C::milliseconds>(tp-dp));
    S::cout << "year        = " << ymd.year() << '\n';
    S::cout << "month       = " << ymd.month() << '\n';
    S::cout << "day         = " << ymd.day() << '\n';
    S::cout << "hour        = " << time.hours().count() << "h\n";
    S::cout << "minute      = " << time.minutes().count() << "min\n";
    S::cout << "second      = " << time.seconds().count() << "s\n";
    S::cout << "millisecond = " << time.subseconds().count() << "ms\n";

这只是为我输出:

2015-07-10 20:10:36.023017
year        = 2015
month       = Jul
day         = 10
hour        = 20h
minute      = 10min
second      = 36s
millisecond = 23ms

另一个更新

这个库成长为 C++ 标准提案,现在处于 C++20 工作草案中。在 C++20 中从 system_clock::time_point 中提取这些字段的语法为:

#include <chrono>

int
main()

    using namespace std::chrono;
    auto tp = system_clock::now();
    auto dp = floor<days>(tp);
    year_month_day ymddp;
    hh_mm_ss timefloor<milliseconds>(tp-dp);
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();

以上假设您希望这些字段采用 UTC。如果您更喜欢在其他时区使用它们,那也是可能的。例如,以下是如何在您计算机当前的本地时区执行此操作:

#include <chrono>

int
main()

    using namespace std::chrono;
    auto tp = zoned_timecurrent_zone(), system_clock::now().get_local_time();
    auto dp = floor<days>(tp);
    year_month_day ymddp;
    hh_mm_ss timefloor<milliseconds>(tp-dp);
    auto y = ymd.year();
    auto m = ymd.month();
    auto d = ymd.day();
    auto h = time.hours();
    auto M = time.minutes();
    auto s = time.seconds();
    auto ms = time.subseconds();

上面唯一的区别是 tp 的构造,它现在具有 local_time 类型,而不是 UTC 示例中的 sys_time。或者,可以通过这个小改动选择任意时区:

auto tp = zoned_time"Europe/London", system_clock::now().get_local_time();

【讨论】:

Howard,IIRC,您正在研究日历课程以扩展 chrono - 这实际上与时钟时间有关。那去哪儿了?我们有机会在 C++14 中看到它吗?谢谢... Fwiw,我在上面的评论中提到的周末时间产生了这个:home.roadrunner.com/~hinnant/date_algorithms.html 这不是约会建议。但它可能会帮助其他人创建约会建议。 在此处作为 GitHub 存储库发布的日期库:github.com/HowardHinnant/date tm local_tm = *localtime(&amp;tt); 通常不是线程安全的(尽管它在 Windows 中) @BitTickler: decltype(std::chrono::system_clock::now())std::chrono::system_clock::time_point,而不是 system_clock::duration。如果您想了解&lt;chrono&gt; 库,我可以提供帮助。如果你只是想咆哮,请教育自己,用事实来咆哮。【参考方案2】:

一旦我想出了这个实现。可能不是最好的,但适用于我的本土项目。

除了从timeinfo 获得的毫秒数和从ms 获得的毫秒数之外的所有数据。

static std::wstring GetDateTime()

    time_t rawtime;
    struct tm timeinfo;
    wchar_t buffer[20];

    time(&rawtime);
    localtime_s(&timeinfo, &rawtime);

    auto now = std::chrono::system_clock::now();
    auto tt = std::chrono::system_clock::to_time_t(now);
    auto nowTruncated = std::chrono::system_clock::from_time_t(tt);
    auto ms = (now - nowTruncated).count();

    wcsftime(buffer, 20, L"%Y-%m-%d %H:%M:%S", &timeinfo);

    return std::wstring(buffer) + L"." + std::to_wstring(ms).substr(0, 3);

示例输出:

2021-06-25 10:18:48.295

【讨论】:

以上是关于从 C++ 中的 std::chrono::time_point 中提取年/月/日等的主要内容,如果未能解决你的问题,请参考以下文章

如何从 c++ 的方面(方面 c++)释放或删除函数中的分配对象?

Lua - C++ 集成:从 C++ 调用表中的函数

从 OpenCV(C++)中的目录读取多个图像

从 Qt (c++) 调用 DLL 中的函数

OpenCV 中的轮廓比较(从 C 到 C++ 的转换)

从 C++ 中的结构到类 [重复]