繁体   English   中英

如何将日期字符串解析为 c++11 std::chrono time_point 或类似的?

[英]How to parse a date string into a c++11 std::chrono time_point or similar?

考虑格式的历史日期字符串:

Thu Jan 9 12:35:34 2014

我想将这样的字符串解析为某种 C++ 日期表示形式,然后计算从那时起经过的时间量。

从产生的持续时间中,我需要访问秒数、分钟数、小时数和天数。

这可以用新的 C++11 std::chrono命名空间完成吗? 如果没有,我今天应该怎么做?

我正在使用 g++-4.8.1,但大概答案应该只针对 C++11 规范。

std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

版本 5 之前的 GCC 不实现std::get_time 您还应该能够编写:

std::tm tm = {};
strptime("Thu Jan 9 2014 12:35:34", "%a %b %d %Y %H:%M:%S", &tm);
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

旧问题的新答案。 新答案的基本原理:该问题已从其原始形式进行了编辑,因为当时的工具无法准确处理所提出的问题。 结果接受的答案给出了与原始问题所要求的略有不同的行为。

我不是要放下已接受的答案。 这是一个很好的答案。 只是C API混乱了,难免会出现这样的错误。

最初的问题是解析"Thu, 9 Jan 2014 12:35:34 +0000" 很明显,目的是解析代表 UTC 时间的时间戳。 但是strptime (它不是标准的 C 或 C++,而是 POSIX)不会解析尾随的 UTC 偏移量,表明这是一个 UTC 时间戳(它将用%z对其进行格式化,但不会对其进行解析)。

然后编辑该问题以询问"Thu Jan 9 12:35:34 2014" 但是没有编辑问题以澄清这是 UTC 时间戳,还是计算机当前本地时区的时间戳。 由于使用了std::mktime ,接受的答案隐含地假定时间戳表示计算机的当前本地时区。

std::mktime不仅将字段类型tm转换为串行类型time_t ,它还执行从计算机本地时区到 UTC 的偏移调整。

但是,如果我们想按照原始(未经编辑)的问题来解析 UTC 时间戳怎么办?

今天可以使用这个更新的免费开源库来完成

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

int
main()
{
    using namespace std;
    using namespace date;
    istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
    sys_seconds tp;
    in >> parse("%a, %d %b %Y %T %z", tp);
}

这个库可以解析%z date::sys_seconds只是一个 typedef:

std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>

问题还问:

从产生的持续时间中,我需要访问秒数、分钟数、小时数和天数。

这部分仍未得到答复。 以下是您如何使用此库进行操作

#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>

int
main()
{
    using namespace std;
    using namespace date;
    istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
    sys_seconds tp;
    in >> parse("%a, %d %b %Y %T %z", tp);
    auto tp_days = floor<days>(tp);
    auto hms = hh_mm_ss<seconds>{tp - tp_days};
    std::cout << "Number of days    = " << tp_days.time_since_epoch() << '\n';
    std::cout << "Number of hours   = " << hms.hours() << '\n';
    std::cout << "Number of minutes = " << hms.minutes() << '\n';
    std::cout << "Number of seconds = " << hms.seconds() << '\n';
}

floor<days>将秒精度time_point截断为days-precision time_point 如果您从tp减去 days-precision time_point ,则剩下的duration表示自午夜 (UTC) 以来的时间。

类型hh_mm_ss<seconds>接受任何可转换为seconds duration seconds (在本例中为从午夜开始的时间),并为每个字段创建一个带有 getter 的{hours, minutes, seconds}字段类型。 如果持续时间的精度比秒更精细,则此字段类型还将具有亚秒的 getter。 在 C++17 之前,必须将更精细的持续时间指定为模板参数。 在 C++17 及更高版本中,可以推导出:

auto hms = hh_mm_ss{tp - tp_days};

最后,您可以打印出所有这些持续时间。 此示例输出:

Number of days    = 16079d
Number of hours   = 12h
Number of minutes = 35min
Number of seconds = 34s

所以 2014-01-09 是 1970-01-01 之后的 16079 天。

这是完整的示例,但精度为milliseconds

#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    using namespace date;

    istringstream in{"Thu, 9 Jan 2014 12:35:34.123 +0000"};
    sys_time<milliseconds> tp;
    in >> parse("%a, %d %b %Y %T %z", tp);
    auto tp_days = floor<days>(tp);
    hh_mm_ss hms{tp - tp_days};
    std::cout << tp << '\n';
    std::cout << "Number of days         = " << tp_days.time_since_epoch() << '\n';
    std::cout << "Number of hours        = " << hms.hours() << '\n';
    std::cout << "Number of minutes      = " << hms.minutes() << '\n';
    std::cout << "Number of seconds      = " << hms.seconds() << '\n';
    std::cout << "Number of milliseconds = " << hms.subseconds() << '\n';
}

输出:

2014-01-09 12:35:34.123
Number of days         = 16079d
Number of hours        = 12h
Number of minutes      = 35min
Number of seconds      = 34s
Number of milliseconds = 123ms

这个库现在是 C++20 的一部分,但在namespace std::chrono并在头文件<chrono>

这是相当C-ish,不像Simple's answer那样优雅的解决方案,但我认为它可能有效。 这个答案可能是错误的,但我会留下它,以便有人可以发表更正。

#include <iostream>
#include <ctime>

int main ()
{
  struct tm timeinfo;
  std::string buffer = "Thu, 9 Jan 2014 12:35:00";

  if (!strptime(buffer.c_str(), "%a, %d %b %Y %T", &timeinfo))
    std::cout << "Error.";

  time_t now;
  struct tm timeinfo2;
  time(&now);
  timeinfo2 = *gmtime(&now);

  time_t seconds = difftime(mktime(&timeinfo2), mktime(&timeinfo));
  time(&seconds);
  struct tm result;
  result = *gmtime ( &seconds );
  std::cout << result.tm_sec << " " << result.tm_min << " "
            << result.tm_hour << " " << result.tm_mday;
  return 0;
}

涵盖的案例(代码如下):

  • 从一个给定日期到现在

    long int min0 = getMinutesSince( "2005-02-19 12:35:00" );

  • 从古至今

    long int min1 = getMinutesSince1970( );

  • 两个日期+小时之间(从纪元到给定日期)

    long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );

    long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );

    cout << min1 - min0 << endl;

完整代码:

#include <iostream>
#include <chrono>
#include <sstream>
#include <string>
#include <iomanip>

using namespace std;

// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970Until( string dateAndHour ) {

  tm tm = {};
  stringstream ss( dateAndHour );
  ss >> get_time(&tm, "%Y-%m-%d  %H:%M:%S");

  chrono::system_clock::time_point tp = chrono::system_clock::from_time_t(mktime(&tm));


  return
    chrono::duration_cast<chrono::minutes>(
                                           tp.time_since_epoch()).count();

} // ()
// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince1970() {
  chrono::system_clock::time_point now = chrono::system_clock::now();

  return
    chrono::duration_cast<chrono::minutes>( now.time_since_epoch() ).count();
} // ()

// ------------------------------------------------
// ------------------------------------------------
long int getMinutesSince( string dateAndHour ) {

  tm tm = {};
  stringstream ss( dateAndHour );
  ss >> get_time(&tm, "%Y-%m-%d  %H:%M:%S");

  chrono::system_clock::time_point then =
    chrono::system_clock::from_time_t(mktime(&tm));

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

  return
    chrono::duration_cast<chrono::minutes>(
                                           now.time_since_epoch()-
                                           then.time_since_epoch()
                                           ).count();
} // ()


// ------------------------------------------------
// ------------------------------------------------
int main () {

  long int min = getMinutesSince1970Until( "1970-01-01 01:01:00" );

  cout << min << endl;


  long int min0 = getMinutesSince1970Until( "2019-01-18 14:23:00" );
  long int min1 = getMinutesSince1970Until( "2019-01-18 14:27:00" );

  if ( (min1 - min0) != 4 ) {
    cout << " something is wrong " << endl;
  } else {
    cout << " it appears to work !" << endl;
  }

  min0 = getMinutesSince( "1970-01-01 01:00:00" );
  min1 = getMinutesSince1970( );

  if ( (min1 - min0) != 0 ) {
    cout << " something is wrong " << endl;
  } else {
    cout << " it appears to work !" << endl;
  }

} // ()

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM