0

入力データの量に応じて、数秒または数日で実行されるプログラムがあります。プログラムの最後に、経過した「クロックウォール」時間を出力したいと思います。1分未満の場合は秒単位、1時間未満の場合は分秒単位、1時間未満の場合は時分秒単位1 日未満、それ以外は日-時-分-秒。私が使用しているコードは次のとおりです。

#include <cstdio>
#include <ctime>
#include <unistd.h> // for sleep

int main (int argc, char ** argv)
{
  time_t startRawTime, endRawTime;

  time (&startRawTime);
  printf ("%s", ctime (&startRawTime));

  sleep (3); // any preprocessing of input data

  time (&endRawTime);
  printf ("%s", ctime (&endRawTime));

  printf ("%.0fs\n", difftime (endRawTime, startRawTime));

  time_t elapsed = static_cast<time_t>(difftime (endRawTime, startRawTime));
  struct tm * ptm = gmtime (&elapsed);
  printf ("%id %ih %im %is\n", ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

  return 0;
}

印刷されるものは次のとおりです。

Mon Apr  9 14:43:16 2012
Mon Apr  9 14:43:19 2012
3s
1d 0h 0m 3s

もちろん、最後の行は間違っています ("0d" のはずです)。印刷することで簡単に解決できそうptm->tm_mday - 1です。ただし、ptm->tm_mday2 つの日付の間に実際に 1 日が経過した場合も「1」になります。その場合、「0d」として表示させたくありません。

それで、これを適切に処理する方法はありますか?または、結果をdifftimedouble (つまり、秒数) として取得してから、秒/分/時間/日の数を自分で計算する必要がありますか?

備考: 私のコードは Linux でのみ使用され、 でコンパイルされていgcc -lstdc++ます。

4

2 に答える 2

3

値は特定のtime_t瞬間を表します。の結果difftimeは、2 つの瞬間の間の間隔 (秒単位) です。それは非常に異なることです。

コードでは、指定された 2 つの時間の間に 3 秒あるため、difftime()が返されます。3.0これを に変換するとtime_t、エポックから 3 秒後の瞬間が得られます。ほとんどのシステムでは、1970 年 1 月 1 日の午前 0 時 GMT の 3 秒後になります。tm_mday値は 1 です。これはその月の最初の日だからです。

は 0 ベースではなく 1 ベースであるため、tm_mday値から 1 を減算することでこれを機能させることができる場合があります。tm_mdayただし、間隔が長くなると意味のない結果が得られます。たとえば、1 月は 31 日あるため、間隔を 31.5 日にすると 2 月 1 日の正午になります。取得しようとしている情報とは関係ありません。

の結果をdifftime()として扱いdouble(それがそのようなものであるため)、単純な算術演算によって日数、時間数、分数、および秒数を計算するだけです。

time_t(移植性がいくらか失われるため、 を使用するのではなく、値を直接減算することができますdifftime()。これにより、一部の算術が少し簡単になりますがtime_t、一部のエポック以降、値が整数の秒数以外の値であるシステムでは機能しなくなります. difftime()理由があります。)

もちろん、最後の行は間違っています ("0d" のはずです)。「ptm->tm_mday - 1」と出力することで簡単に解決できるようです。ただし、2 つの日付の間に実際に 1 日が経過した場合、ptm->tm_mday も「1」になります。その場合、「0d」として表示させたくありません。

それは正しくありません。時間間隔が 1 日を少し超える場合は、ptm->tm_mdayになります2。これは、コードを少し変更することで確認できます。

time (&endRawTime);
endRawTime += 86400; // add this line
printf ("%s", ctime (&endRawTime));

この変更を行うと、次の出力が得られます。

Mon Apr  9 13:56:49 2012
Tue Apr 10 13:56:52 2012
86403s
2d 0h 0m 3s

これは から 1 を引くことで修正できますptm->tm_mday。しかし、繰り返しますが、それは正しいアプローチではありません。

于 2012-04-09T20:51:40.940 に答える
1

<chrono>これは、あなたが犯しているような間違いを防ぐタイプセーフなタイミングライブラリであるライブラリを使用した例です。chrono では、time_points と durations は互換性がありません。そのように使用しようとすると、コンパイラ エラーが発生します。

#include <chrono>
#include <iostream>
#include <thread>
#include <cassert>

template<typename Rep,typename Period>
void print_duration(std::chrono::duration<Rep,Period> t) {
    assert(0<=t.count() && "t must be >= 0");

    // approximate because a day doesn't have a fixed length
    typedef std::chrono::duration<int,std::ratio<60*60*24>> days;

    auto d = std::chrono::duration_cast<days>(t);
    auto h = std::chrono::duration_cast<std::chrono::hours>(t - d);
    auto m = std::chrono::duration_cast<std::chrono::minutes>(t - d - h);
    auto s = std::chrono::duration_cast<std::chrono::seconds>(t - d - h - m);
    if(t>=days(1))
        std::cout << d.count() << "d ";
    if(t>=std::chrono::hours(1))
        std::cout << h.count() << "h ";
    if(t>=std::chrono::minutes(1))
        std::cout << m.count() << "m ";
    std::cout << s.count() << "s";
}

int main() {
    auto start = std::chrono::steady_clock::now();
    std::this_thread::sleep_for(std::chrono::seconds(3));
    auto finish = std::chrono::steady_clock::now();

    print_duration(finish-start);
    std::cout << '\n';
}

GCC に関する注意事項

古いバージョンの GCC には、steady_clock の代わりに monotonic_clock があります。4.7にはsteady_clockがあります。

std::this_thread::sleep_for にアクセスするには、何らかの理由で _GLIBCXX_USE_NANOSLEEP を定義する必要がある場合があります。

于 2012-04-09T21:26:03.567 に答える