0

根据输入数据的数量,我有一个可以在几秒或几天内运行的程序。在我的程序结束时,我想打印经过的“时钟墙”时间:如果小于一分钟,则以秒为单位,如果小于一小时,则以分钟和秒为单位,如果是,则以小时-分钟-秒为单位少于 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_mday当两个日期之间确实经过了一天时,也将是“1”。所以在那种情况下,我不想让它显示为“0d”。

那么有没有办法正确处理这个问题?或者我应该得到difftime双倍的结果(即秒数),然后计算自己的秒/分钟/小时/天数?

备注:我的代码仅在 Linux 上使用,使用gcc -lstdc++.

4

2 回答 2

3

一个time_t值代表一个特定的时刻。结果difftime是两个时刻之间的间隔,以秒为单位。那是非常不同的事情。

在您的代码中,difftime()返回3.0,因为两个指定时间之间有 3 秒。将其转换time_t为 epoch 后 3 秒的时间;在大多数系统上,这将是 1970 年 1 月 1 日格林威治标准时间午夜后 3 秒。该tm_mday值为 1,因为那是该月的第一天。

您可以通过从tm_mday值中减去 1 来完成这项工作,因为tm_mday它是基于 1 而不是基于 0。但是对于更长的时间间隔,您仍然会得到毫无意义的结果。例如,间隔 31.5 天会给你 2 月 1 日中午,因为 1 月有 31 天;这与您尝试获取的信息无关。

只需将结果difftime()视为 a double(因为它就是这样)并通过简单的算术计算天数、小时数、分钟数和秒数。

(由于一些可移植性的损失,您可以直接减去这些time_t值而不是使用difftime()。这将使一些算术更容易一些,但它会在time_t值不是自某个时期以来的整数秒计数的系统上中断. difftime()存在是有原因的。)

当然最后一行是错误的(应该是“0d”)。似乎可以通过打印“ptm->tm_mday - 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 有 monotonic_clock 而不是 stable_clock。4.7 有 stable_clock。

为了访问 std::this_thread::sleep_for ,您可能出于某种原因必须定义 _GLIBCXX_USE_NANOSLEEP 。

于 2012-04-09T21:26:03.567 回答