C中的格式化经过时间

Formatted elapsed time in C

我正在编写一个函数,除其他外,它必须打印出经过的时间计数器。它通过引用接收开始时间 _start,并将其与 current 进行比较,两者的类型均为 time_t。我想使用 strftime() 以 ISO 8601 格式打印出观察到的时间增量。这是我尝试做的事情:

// Negative start time implies program has not begun
if (*_start > 0) {
    time_t elapsed = current - *_start;
    strftime(time_str, sizeof(time_str) - 1, "%T", localtime(&elapsed));
    printf("%s\n", time_str);
}

这是我在 运行 运行程序

后立即得到的输出
01:00:00
01:00:00
01:00:01
01:00:01
01:00:01

秒工作正常,如果我让它 运行 更长,它们会按预期增加,分钟也是如此,但是小时从 01 开始,而不是 00。为什么会这样?我怎样才能让开始的时间像分钟一样归零?

time_t 通常(请参阅编辑)存储绝对时间戳(自 1970 年 1 月 1 日午夜 UTC 以来的秒数)。通过计算 current - *_start,您将获得以秒为单位的经过时间(根据需要),但是通过将其传递给 localtimestrftime,您是在告诉计算机计算经过的时间自程序开始以来并将其视为自 UTC 1-1-1970 午夜以来经过的时间。

我猜这恰好是 01:00:00 在您系统的本地时区。

我不知道 C99 有打印经过时间的函数,但自己写一个并不难。

void format_elapsed_time(char *time_str, int total_seconds_elapsed) {
    int hours_elapsed = total_seconds_elapsed / 3600;
    int minutes_elapsed = (total_seconds_elapsed % 3600) / 60;
    int seconds_elapsed = total_seconds_elapsed % 60;
    sprintf(time_str, "%02i:%02i:%02i", hours_elapsed, minutes_elapsed, seconds_elapsed);
}

编辑:正如@chux 指出的那样,time_t 不必将时间戳存储为自 1-1-1970 以来的秒数。有关详细信息,请参阅 this answer

要方便地查找 2 time_t 之间经过的秒数,请使用 difftime() 因为 C 中未指定减去 2 time_t 值作为秒数差。

double difftime(time_t time1, time_t time0); C11dr §7.26.2.2
The difftime function returns the difference expressed in seconds as a double.

double elapsed_seconds = difftime(current, *_start);
printf("elapsed_seconds: %f\n", elapsed_seconds);

如果你想使用这个方法,你应该知道time() returns UTC。如果您随后从 local 时间(由 localtime() 返回)中减去该时间,时区将对结果产生影响(很可能您的特定时区已从 UTC 中删除一小时)。

考虑以下与您的代码段类似的完整程序:

#include <stdio.h>
#include <time.h>
#include <unistd.h>

int main(void) {
    time_t start = time(0);
    char time_str[100];
    for (int i = 5; i > 0; i--) {
        sleep (1);
        time_t elapsed = time(0) - start;
        strftime(time_str, sizeof(time_str) - 1, "%T", localtime(&elapsed));
        printf("%s\n", time_str);
    }

    return 0;
}

还要考虑到我的特定时区与 UTC 相差八小时:

pax> date ; date -u
Thursday 30 March  10:25:57 AWST 2017
Thursday 30 March  02:25:57 UTC 2017

当我 运行 它时,我看到:

08:00:01
08:00:02
08:00:03
08:00:04
08:00:05

您可以在那里看到与 UTC 的八小时时差会影响该值。 fix 实际上很简单:根本不使用本地时间。如果将 localtime() 调用替换为 gmtime(),您将获得预期的输出:

00:00:01
00:00:02
00:00:03
00:00:04
00:00:05

我意识到这个问题已经有了答案,但我想我可能会稍微转移一下注意力并扩展已接受的答案。由于 OP 指定他们正在处理 经过时间 ,因此可以避免使用 clock() 函数完全处理绝对时间戳。

clock_t start = clock();
.
.
clock_t end = clock();
double elapsed = (end - start) / (double)CLOCKS_PER_SEC;

然后你可以调用概念上修改过的 format_elapsed_time() 函数,像这样:

void format_elapsed_time(char *time_str, double elapsed) {
    int h, m, s, ms;

    h = m = s = ms = 0;
    ms = elapsed * 1000; // promote the fractional part to milliseconds
    h = ms / 3600000;
    ms -= (h * 3600000);
    m = ms / 60000;
    ms -= (m * 60000);
    s = ms / 1000;
    ms -= (s * 1000);
    sprintf(time_str, "%02i:%02i:%02i.%03i", h, m, s, ms);
}