如何将std :: chrono :: time_point转换为带有小数秒的日历日期时间字符串?

box*_*oxx 51 c++ datetime std c++11 c++-chrono

如何将std :: chrono :: time_point转换为带有小数秒的日历日期时间字符串?例如:"10-10-2012 12:38:40.123456".

Aki*_*shi 62

如果是system_clock,这个类有time_t转换.

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

using namespace std::chrono;

int main()
{
  system_clock::time_point p = system_clock::now();

  std::time_t t = system_clock::to_time_t(p);
  std::cout << std::ctime(&t) << std::endl; // for example : Tue Sep 27 14:21:13 2011
}
Run Code Online (Sandbox Code Playgroud)

示例结果:

Thu Oct 11 19:10:24 2012
Run Code Online (Sandbox Code Playgroud)

编辑:但是,time_t不包含小数秒.另一种方法是使用time_point :: time_since_epoch()函数.此函数从epoch返回持续时间.以下示例是毫秒秒分辨率的分数.

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

using namespace std::chrono;

int main()
{
  high_resolution_clock::time_point p = high_resolution_clock::now();

  milliseconds ms = duration_cast<milliseconds>(p.time_since_epoch());

  seconds s = duration_cast<seconds>(ms);
  std::time_t t = s.count();
  std::size_t fractional_seconds = ms.count() % 1000;

  std::cout << std::ctime(&t) << std::endl;
  std::cout << fractional_seconds << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

示例结果:

Thu Oct 11 19:10:24 2012

925
Run Code Online (Sandbox Code Playgroud)

  • 有关信息,`std :: ctime`不是线程安全的,根据[cppreference](http://en.cppreference.com/w/cpp/chrono/c/ctime),POSIX将其标记为过时. (5认同)

How*_*ant 32

首先创建一个std::tm对应于10-10-2012 12:38:40的自解释代码,将其转换为a std::chrono::system_clock::time_point,添加0.123456秒,然后通过转换回a打印出来std::tm.如何处理小数秒是最后一步.

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

int main()
{
    // Create 10-10-2012 12:38:40 UTC as a std::tm
    std::tm tm = {0};
    tm.tm_sec = 40;
    tm.tm_min = 38;
    tm.tm_hour = 12;
    tm.tm_mday = 10;
    tm.tm_mon = 9;
    tm.tm_year = 112;
    tm.tm_isdst = -1;
    // Convert std::tm to std::time_t (popular extension)
    std::time_t tt = timegm(&tm);
    // Convert std::time_t to std::chrono::system_clock::time_point
    std::chrono::system_clock::time_point tp = 
                                     std::chrono::system_clock::from_time_t(tt);
    // Add 0.123456 seconds
    // This will not compile if std::chrono::system_clock::time_point has
    //   courser resolution than microseconds
    tp += std::chrono::microseconds(123456);

    // Now output tp

    // Convert std::chrono::system_clock::time_point to std::time_t
    tt = std::chrono::system_clock::to_time_t(tp);
    // Convert std::time_t to std::tm (popular extension)
    tm = std::tm{0};
    gmtime_r(&tt, &tm);
    // Output month
    std::cout << tm.tm_mon + 1 << '-';
    // Output day
    std::cout << tm.tm_mday << '-';
    // Output year
    std::cout << tm.tm_year+1900 << ' ';
    // Output hour
    if (tm.tm_hour <= 9)
        std::cout << '0';
    std::cout << tm.tm_hour << ':';
    // Output minute
    if (tm.tm_min <= 9)
        std::cout << '0';
    std::cout << tm.tm_min << ':';
    // Output seconds with fraction
    //   This is the heart of the question/answer.
    //   First create a double-based second
    std::chrono::duration<double> sec = tp - 
                                    std::chrono::system_clock::from_time_t(tt) +
                                    std::chrono::seconds(tm.tm_sec);
    //   Then print out that double using whatever format you prefer.
    if (sec.count() < 10)
        std::cout << '0';
    std::cout << std::fixed << sec.count() << '\n';
}
Run Code Online (Sandbox Code Playgroud)

对我来说这个输出:

10-10-2012 12:38:40.123456
Run Code Online (Sandbox Code Playgroud)

std::chrono::system_clock::time_point可能会或可能不会精确到足以保持微秒.

更新

更简单的方法是使用此日期库.代码简化为(使用C++ 14持续时间文字):

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

int
main()
{
    using namespace date;
    using namespace std::chrono;
    auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
    static_assert(std::is_same<decltype(t),
                               time_point<system_clock, microseconds>>{}, "");
    std::cout << t << '\n';
}
Run Code Online (Sandbox Code Playgroud)

哪个输出:

2012-10-10 12:38:40.123456
Run Code Online (Sandbox Code Playgroud)

static_assert如果您不需要证明类型t是a ,您可以跳过std::chrono::time_point.

如果输出不符合您的喜好,例如您真的喜欢dd-mm-yyyy订购,您可以:

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

int
main()
{
    using namespace date;
    using namespace std::chrono;
    using namespace std;
    auto t = sys_days{10_d/10/2012} + 12h + 38min + 40s + 123456us;
    auto dp = floor<days>(t);
    auto time = make_time(t-dp);
    auto ymd = year_month_day{dp};
    cout.fill('0');
    cout << ymd.day() << '-' << setw(2) << static_cast<unsigned>(ymd.month())
         << '-' << ymd.year() << ' ' << time << '\n';
}
Run Code Online (Sandbox Code Playgroud)

它给出了所要求的输出:

10-10-2012 12:38:40.123456
Run Code Online (Sandbox Code Playgroud)

更新

以下是如何以毫秒精度整齐地格式化当前时间UTC:

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

int
main()
{
    using namespace std::chrono;
    std::cout << date::format("%F %T\n", time_point_cast<milliseconds>(system_clock::now()));
}
Run Code Online (Sandbox Code Playgroud)

只为我输出:

2016-10-17 16:36:02.975
Run Code Online (Sandbox Code Playgroud)

C++ 17将允许您更换time_point_cast<milliseconds>floor<milliseconds>.在此之前date::floor可用"date.h".

std::cout << date::format("%F %T\n", date::floor<milliseconds>(system_clock::now()));
Run Code Online (Sandbox Code Playgroud)

  • 这是在向C++标准委员会提出的过程中:https://howardhinnant.github.io/date/d0355r1.html (5认同)

Ant*_*ams 7

一般来说,你不能以任何直截了当的方式做到这一点.time_point基本上只是一个duration来自特定时钟的时代.

如果你有std::chrono::system_clock::time_point,那么你可以使用std::chrono::system_clock::to_time_t转换time_point为a time_t,然后使用普通的C函数,如ctimestrftime格式化它.


示例代码:

std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(tp);
std::tm timetm = *std::localtime(&time);
std::cout << "output : " << std::put_time(&timetm, "%c %Z") << "+"
          << std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch()).count() % 1000 << std::endl;
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案的问题是std :: localtime不是线程安全的。 (2认同)

Dar*_*nas 5

这对我来说适用于像 YYYY.MM.DD-HH.MM.SS.fff 这样的格式。尝试使这段代码能够接受任何字符串格式就像重新发明轮子一样(即 Boost.

std::chrono::system_clock::time_point string_to_time_point(const std::string &str)
{
    using namespace std;
    using namespace std::chrono;

    int yyyy, mm, dd, HH, MM, SS, fff;

    char scanf_format[] = "%4d.%2d.%2d-%2d.%2d.%2d.%3d";

    sscanf(str.c_str(), scanf_format, &yyyy, &mm, &dd, &HH, &MM, &SS, &fff);

    tm ttm = tm();
    ttm.tm_year = yyyy - 1900; // Year since 1900
    ttm.tm_mon = mm - 1; // Month since January 
    ttm.tm_mday = dd; // Day of the month [1-31]
    ttm.tm_hour = HH; // Hour of the day [00-23]
    ttm.tm_min = MM;
    ttm.tm_sec = SS;

    time_t ttime_t = mktime(&ttm);

    system_clock::time_point time_point_result = std::chrono::system_clock::from_time_t(ttime_t);

    time_point_result += std::chrono::milliseconds(fff);
    return time_point_result;
}

std::string time_point_to_string(std::chrono::system_clock::time_point &tp)
{
    using namespace std;
    using namespace std::chrono;

    auto ttime_t = system_clock::to_time_t(tp);
    auto tp_sec = system_clock::from_time_t(ttime_t);
    milliseconds ms = duration_cast<milliseconds>(tp - tp_sec);

    std::tm * ttm = localtime(&ttime_t);

    char date_time_format[] = "%Y.%m.%d-%H.%M.%S";

    char time_str[] = "yyyy.mm.dd.HH-MM.SS.fff";

    strftime(time_str, strlen(time_str), date_time_format, ttm);

    string result(time_str);
    result.append(".");
    result.append(to_string(ms.count()));

    return result;
}
Run Code Online (Sandbox Code Playgroud)