以C为单位的格式化经过时间

时间:2017-03-30 01:45:28

标签: c time c99 strftime

我正在编写一个函数,除其他外,必须打印出已用时间计数器。它通过引用接收开始时间_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.为什么会发生这种情况?我怎样才能让时间开始归零,比如分钟?

4 个答案:

答案 0 :(得分:3)

time_t通常(参见编辑)存储绝对时间戳(自UTC,1970年1月1日午夜起的秒数)。通过计算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

答案 1 :(得分:1)

为了便于查找2 time_t之间经过的秒数,请使用difftime()作为减去2 time_t值,但未在C中指定为秒的差异。

  

double difftime(time_t time1, time_t time0);C11dr§7.26.2.2
  difftime函数返回以秒为单位的差值double

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

答案 2 :(得分:1)

如果您想使用此方法,您应该知道time()返回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的8小时时差影响该值。 修复实际上非常简单:根本不使用本地时间。如果您使用localtime()替换gmtime()来电,则会获得您期望的输出:

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

答案 3 :(得分:0)

我意识到这个问题已经有了答案,但我想我可能会把焦点转移一点,然后扩展接受的答案。由于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);
}