简体   繁体   English

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

[英]How to convert std::chrono::time_point to calendar datetime string with fractional seconds?

How to convert std::chrono::time_point to calendar datetime string with fractional seconds?如何将std::chrono::time_point转换为带小数秒的日历日期时间字符串?

For example:例如:

"10-10-2012 12:38:40.123456"

If system_clock, this class have time_t conversion.如果是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
}

example result:示例结果:

Thu Oct 11 19:10:24 2012

EDIT: But, time_t does not contain fractional seconds.编辑:但是, time_t 不包含小数秒。 Alternative way is to use time_point::time_since_epoch() function.另一种方法是使用 time_point::time_since_epoch() 函数。 This function returns duration from epoch.此函数返回纪元的持续时间。 Follow example is milli second resolution's fractional.下面的例子是毫秒分辨率的小数。

#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;
}

example result:示例结果:

Thu Oct 11 19:10:24 2012

925

Self-explanatory code follows which first creates a std::tm corresponding to 10-10-2012 12:38:40, converts that to a std::chrono::system_clock::time_point , adds 0.123456 seconds, and then prints that out by converting back to a std::tm .不言自明的代码如下,首先创建一个对应于 10-10-2012 12:38:40 的std::tm ,将其转换为std::chrono::system_clock::time_point ,加上 0.123456 秒,然后将其打印出来通过转换回std::tm How to handle the fractional seconds is in the very last step.如何处理小数秒是最后一步。

#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';
}

For me this outputs:对我来说,这个输出:

10-10-2012 12:38:40.123456

Your std::chrono::system_clock::time_point may or may not be precise enough to hold microseconds.您的std::chrono::system_clock::time_point可能不够精确以保持微秒。

Update更新

An easier way is to just use this date library .一个更简单的方法是使用这个日期库 The code simplifies down to (using C++14 duration literals):代码简化为(使用 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';
}

which outputs:输出:

2012-10-10 12:38:40.123456

You can skip the static_assert if you don't need to prove that the type of t is a std::chrono::time_point .如果您不需要证明t的类型是std::chrono::time_point ,则可以跳过static_assert

If the output isn't to your liking, for example you would really like dd-mm-yyyy ordering, you could:如果输出不符合您的喜好,例如您真的很喜欢 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';
}

which gives exactly the requested output:它给出了所请求的输出:

10-10-2012 12:38:40.123456

Update更新

Here is how to neatly format the current time UTC with milliseconds precision:以下是如何以毫秒精度巧妙地格式化当前时间 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()));
}

which just output for me:这只是为我输出:

2016-10-17 16:36:02.975

C++17 will allow you to replace time_point_cast<milliseconds> with floor<milliseconds> . C++17 将允许你用time_point_cast<milliseconds>替换time_point_cast<milliseconds> floor<milliseconds> Until then date::floor is available in "date.h" .在那date::floor"date.h"可用。

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

Update C++20更新 C++20

In C++20 this is now simply:在 C++20 中,这现在很简单:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    auto t = sys_days{10d/10/2012} + 12h + 38min + 40s + 123456us;
    std::cout << t << '\n';
}

Or just:要不就:

std::cout << std::chrono::system_clock::now() << '\n';

std::format will be available to customize the output. std::format将可用于自定义输出。

In general, you can't do this in any straightforward fashion.通常,您不能以任何简单的方式执行此操作。 time_point is essentially just a duration from a clock-specific epoch. time_point本质上只是一个特定于时钟的纪元的duration

If you have a std::chrono::system_clock::time_point , then you can use std::chrono::system_clock::to_time_t to convert the time_point to a time_t , and then use the normal C functions such as ctime or strftime to format it.如果你有一个std::chrono::system_clock::time_point ,那么你可以使用std::chrono::system_clock::to_time_ttime_point转换为time_t ,然后使用普通的 C 函数如ctimestrftime来格式化它。


Example code:示例代码:

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;

This worked for me for a format like YYYY.MM.DD-HH.MM.SS.fff.这对我来说适用于 YYYY.MM.DD-HH.MM.SS.fff 这样的格式。 Attempting to make this code capable of accepting any string format will be like reinventing the wheel (ie there are functions for all this in Boost.试图让这段代码能够接受任何字符串格式就像重新发明轮子一样(即在 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;
}

I would have put this in a comment on the accepted answer, since that's where it belongs, but I can't.我会把它放在对接受的答案的评论中,因为那是它所属的地方,但我不能。 So, just in case anyone gets unreliable results, this could be why.所以,万一有人得到不可靠的结果,这可能就是原因。

Be careful of the accepted answer, it fails if the time_point is before the epoch.请注意接受的答案,如果 time_point 在纪元之前,则它会失败。

This line of code:这行代码:

std::size_t fractional_seconds = ms.count() % 1000;

will yield unexpected values if ms.count() is negative (since size_t is not meant to hold negative values).如果 ms.count() 为负数(因为 size_t 并不意味着保持负值),则会产生意外的值。

In my case I use chrono and c function localtime_r which is thread-safe (in opposition to std::localtime).就我而言,我使用 chrono 和 c 函数 localtime_r,它是线程安全的(与 std::localtime 相对)。

#include <iostream>
#include <chrono>
#include <ctime>
#include <time.h>
#include <iomanip>


int main() {
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
  std::chrono::milliseconds now2 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
  struct tm currentLocalTime;
  localtime_r(&currentTime, &currentLocalTime);
  char timeBuffer[80];
  std::size_t charCount { std::strftime( timeBuffer, 80,
                                         "%b %d %T",
                                          &currentLocalTime)
                         };

  if (charCount == 0) return -1;

  std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
  return 0;
}

If you are to format a system_clock::time_point in the format of numpy datetime64, you could use:如果要以 numpy datetime64 格式格式化system_clock::time_point ,可以使用:

std::string format_time_point(system_clock::time_point point)
{
    static_assert(system_clock::time_point::period::den == 1000000000 && system_clock::time_point::period::num == 1);
    std::string out(29, '0');
    char* buf = &out[0];
    std::time_t now_c = system_clock::to_time_t(point);
    std::strftime(buf, 21, "%Y-%m-%dT%H:%M:%S.", std::localtime(&now_c));
    sprintf(buf+20, "%09ld", point.time_since_epoch().count() % 1000000000);
    return out;
}

sample output: 2019-11-19T17:59:58.425802666样本输出: 2019-11-19T17:59:58.425802666

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将分数纪元时间戳(double)转换为std :: chrono :: time_point? - How to convert a fractional epoch timestamp (double) to an std::chrono::time_point? std :: string到std :: chrono time_point - std::string to std::chrono time_point 如何正确地将字符串转换为 std::chrono::system_clock::time_point? - How to properly convert string to std::chrono::system_clock::time_point? 如何在不使用数组的情况下将 chrono::time_point 转换为字符串? - how to convert chrono::time_point to string without using array? 将 C# 日期时间转换为 C++ std::chrono::system_clock::time_point - Convert C# DateTime to C++ std::chrono::system_clock::time_point 有没有一种标准方法可以在不使用Boost的情况下将std :: string转换为std :: chrono :: time_point? - Is there a standard way to convert a std::string to std::chrono::time_point without using Boost? std :: string中的std :: chrono :: time_point - std::chrono::time_point from std::string 如何在不使用time_t的情况下将std :: chrono :: time_point转换为std :: tm? - How to convert std::chrono::time_point to std::tm without using time_t? 无法在 std::chrono::time_point 之间转换 - Cannot convert between std::chrono::time_point s 将std :: chrono :: time_point转换为unix时间戳 - Convert std::chrono::time_point to unix timestamp
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM