web-dev-qa-db-ja.com

日付文字列をC ++ 11 std :: chrono time_pointなどに解析する方法は?

形式の歴史的な日付文字列を考えてみましょう:

Thu Jan 9 12:35:34 2014

そのような文字列を何らかのC++日付表現に解析し、それから経過した時間を計算したいと思います。

結果の期間から、秒、分、時間、日数にアクセスする必要があります。

これは、新しいC++ 11 std::chrono名前空間?そうでない場合、今日これについてどうすればよいですか?

私はg ++-4.8.1を使用していますが、おそらく答えはC++ 11仕様のみを対象としているはずです。

38
Drew Noakes
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));
62
Simple

古い質問に対する新しい回答。新しい答えの理由:当時のツールは、求められていたものを正確に処理できないため、質問は元の形式から編集されました。そして、結果として受け入れられた答えは、元の質問が要求したものとは微妙に異なる動作を与えます。

私は受け入れられた答えを書き下ろそうとはしていません。それは良い答えです。 C APIがsoであるというだけで、このような間違いが発生することは避けられません。

元の質問は、"Thu, 9 Jan 2014 12:35:34 +0000"を解析することでした。したがって、意図はUTC時間を表すタイムスタンプを解析することでした。ただし、strptime(標準CまたはC++ではないがPOSIX)は、これがUTCタイムスタンプであることを示す後続のUTCオフセットを解析しません(%zでフォーマットしますが、解析はしません) )。

その後、質問は"Thu Jan 9 12:35:34 2014"について尋ねるように編集されました。しかし、質問はnot編集され、これがUTCタイムスタンプか、コンピューターの現在のlocalタイムゾーンのタイムスタンプかを明確にしました。受け入れられた回答implicitlyは、std::mktimeを使用しているため、タイムスタンプがコンピューターの現在のローカルタイムゾーンを表していると想定しています。

std::mktimeは、フィールドタイプtmをシリアルタイプtime_tに変換するだけでなく、コンピューターのローカルタイムゾーンからUTCへのオフセット調整も実行します。

しかし、元の(未編集の)質問に応じてUTCタイムスタンプを解析したい場合はどうでしょうか?

これは、この新しい 無料のオープンソースライブラリ を使用して今日実行できます。

#include "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);
}

このライブラリcan%zを解析します。 date::sys_secondsは次の型定義にすぎません:

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

質問はまた尋ねます:

結果の期間から、秒、分、時間、日数にアクセスする必要があります。

その部分は未回答のままです。 このライブラリ を使用して行う方法は次のとおりです。このパートでは、2番目の header-only library "chrono_io.h" を使用します。

#include "chrono_io.h"
#include "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);
    auto tp_days = floor<days>(tp);
    auto hms = make_time(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_pointdays-precisiontime_pointに切り捨てます。 tpから日精度time_pointを引くと、深夜(UTC)からの時間を表すdurationが残ります。

ファクトリ関数make_timeduration(この場合は午前0時からの時間)を取り、各フィールドのゲッターを含む{hours, minutes, seconds}フィールドタイプを作成します。期間の精度が秒よりも細かい場合、このフィールドタイプにはサブ秒のゲッターも含まれます。

最後に、 "chrono_io.h" を使用すると、これらの期間をすべて出力できます。この例の出力:

Number of days    = 16079[86400]s
Number of hours   = 12h
Number of minutes = 35min
Number of seconds = 34s

[86400]sは、日単位の精度を持つdurationの単位を表します。 2014-01-09は1970-01-01の16079日後です。

11
Howard Hinnant

これはかなりCっぽく、Simpleの答えほどエレガントではありませんが、うまくいくと思います。 この答えはおそらく間違っていますが、誰かが修正を投稿できるように、私はそれを残しておきます。

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

カバーされているケース(コードは以下):

  • 今までの贈与日から

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

  • エポックから今まで

    long int min1 = getMinutesSince1970( );

  • 2つの日付と時間の間(エポックは特定の日付まで)

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

} // ()
0
cibercitizen1