哪种格式字符串与printf()一起使用的时间为789:01.234

时间:2019-06-27 19:48:19

标签: c time formatting printf

我想从一个双精度点上打印一个以分钟和秒为单位的时间,包括它们的小数部分,最多6位,并且不带尾随零。

由于格式的性质,应该有可能在单个printf()语句中将解决方案嵌套在其他参数中!

我要打印的时间变量是秒单位的两倍,并且不超过几十小时的范围。

    double time1 = 123.456789; //   2:03.456789 some text
    double time2 = 12345.6;    // 205:45.6 some text
    printf("format: %-16s time1: %.6g some text\n", "%.6g", time1);
    printf("format: %-16s time2: %.6g some text\n", "%.6g", time2);
    printf("format: %-16s time1: %3d:%09.6f some text\n", "%3d:%09.6f", (int)time1 / 60, fmod(time1, 60));
    printf("format: %-16s time2: %3d:%09.6f some text\n", "%3d:%09.6f", (int)time2 / 60, fmod(time2, 60));
    printf("format: %-16s time1: %3d:%09.6g some text\n", "%3d:%09.6g", (int)time1 / 60, fmod(time1, 60));
    printf("format: %-16s time2: %3d:%09.6g some text\n", "%3d:%09.6g", (int)time2 / 60, fmod(time2, 60));
    printf("format: %-16s time1: %3d:%0.6g some text\n", "%3d:%0.6g", (int)time1 / 60, fmod(time1, 60));
    printf("format: %-16s time2: %3d:%0.6g some text\n", "%3d:%0.6g", (int)time2 / 60, fmod(time2, 60));
    printf("format: %-16s time1: %3d:%02d%.6f some text\n", "%3d:%02d%.6f", (int)time1 / 60, (int)time1 % 60, fmod(time1, 1));
    printf("format: %-16s time2: %3d:%02d%.6f some text\n", "%3d:%02d%.6f", (int)time2 / 60, (int)time2 % 60, fmod(time2, 1));
    printf("format: %-16s time1: %3d:%02d%.6g some text\n", "%3d:%02d%.6g", (int)time1 / 60, (int)time1 % 60, fmod(time1, 1));
    printf("format: %-16s time2: %3d:%02d%.6g some text\n", "%3d:%02d%.6g", (int)time2 / 60, (int)time2 % 60, fmod(time2, 1));
    printf("format: %-16s time1: %3d:%02d%0.6g some text\n", "%3d:%02d%0.6g", (int)time1 / 60, (int)time1 % 60, fmod(time1, 1));
    printf("format: %-16s time2: %3d:%02d%0.6g some text\n", "%3d:%02d%0.6g", (int)time2 / 60, (int)time2 % 60, fmod(time2, 1));

预期:

time1:   2:03.456789 some text
time2: 205:45.6 some text

结果:

format: %.6g             time1: 123.457 some text
format: %.6g             time2: 12345.6 some text
format: %3d:%09.6f       time1:   2:03.456789 some text   <- OK
format: %3d:%09.6f       time2: 205:45.600000 some text   <- trailing zeros
format: %3d:%09.6g       time1:   2:003.45679 some text   <- 3 digits for minutes, missing 8
format: %3d:%09.6g       time2: 205:0000045.6 some text   <- 7 digits for minutes
format: %3d:%0.6g        time1:   2:3.45679 some text     <- 1 digit for minutes, missing 8
format: %3d:%0.6g        time2: 205:45.6 some text        <- OK
format: %3d:%02d%.6f     time1:   2:030.456789 some text  <- leading 0
format: %3d:%02d%.6f     time2: 205:450.600000 some text  <- leading 0, trailing zeros
format: %3d:%02d%.6g     time1:   2:030.456789 some text  <- leading 0
format: %3d:%02d%.6g     time2: 205:450.6 some text       <- leading 0
format: %3d:%02d%0.6g    time1:   2:030.456789 some text  <- leading 0
format: %3d:%02d%0.6g    time2: 205:450.6 some text       <- leading 0

另一种格式会很好:

time2: 3:25:45.6 some text

3 个答案:

答案 0 :(得分:5)

对于正时间值,请尝试以下格式:

main

但是请注意,如果分数值大于或等于printf("%d:%d%g\n", (int)time / 60, // number of minutes (int)time % 60 / 10, // number of tens of seconds time - (int)time / 10 * 10); // number of seconds units and fraction thereof ,这将不起作用,因为最后一项将舍入到下一个整数。

将时间转换为整数微秒并以这种方式打印会更安全:

0.9999995

用这种方法去除尾随零会更麻烦,恐怕使用函数会更好。正确处理无限值和nan等极端情况并保持正确的舍入是很难的。

这是一个带有测试程序的示例:

int us = (int)(time * 1000000 + 0.5);
printf("%d:%02d.%06d\n", us / 60000000, us / 1000000 % 60, us % 1000000);

输出:

                               0 --> 0:00
                              -0 --> -0:00
                               1 --> 0:01
                              -1 --> -0:01
                              59 --> 0:59
                             -59 --> -0:59
                              60 --> 1:00
                             -60 --> -1:00
                              61 --> 1:01
                             -61 --> -1:01
                           121.1 --> 2:01.1
                          -121.1 --> -2:01.1
                          121.11 --> 2:01.11
                         -121.11 --> -2:01.11
                         121.111 --> 2:01.111
                        -121.111 --> -2:01.111
                        121.1111 --> 2:01.1111
                       -121.1111 --> -2:01.1111
                       121.11111 --> 2:01.11111
                      -121.11111 --> -2:01.11111
                      121.111111 --> 2:01.111111
                     -121.111111 --> -2:01.111111
                            4321 --> 72:01
                           -4321 --> -72:01
                         12345.6 --> 205:45.6
                        -12345.6 --> -205:45.6
                      123.456789 --> 2:03.456789
                     -123.456789 --> -2:03.456789
                     129.9999994 --> 2:09.999999
                    -129.9999994 --> -2:09.999999
                     129.9999995 --> 2:10
                    -129.9999995 --> -2:10
                     599.9999994 --> 9:59.999999
                    -599.9999994 --> -9:59.999999
               599.9999994999999 --> 9:59.999999
              -599.9999994999999 --> -9:59.999999
                    599.99999951 --> 10:00
                   -599.99999951 --> -10:00
                     599.9999999 --> 10:00
                    -599.9999999 --> -10:00
                   23.9999999999 --> 0:24
                  -23.9999999999 --> -0:24
                      59.9999994 --> 0:59.999999
                     -59.9999994 --> -0:59.999999
                      59.9999996 --> 1:00
                     -59.9999996 --> -1:00
               999.0000005000001 --> 16:39.000001
              -999.0000005000001 --> -16:39.000001
                    1000.0000005 --> 16:40.000001
                   -1000.0000005 --> -16:40.000001
                     999.9999999 --> 16:40
                    -999.9999999 --> -16:40
                         1000000 --> 16666:40
                        -1000000 --> -16666:40
                     10000000000 --> 166666666:40
                    -10000000000 --> -166666666:40
                   1000000000000 --> 16666666666:40
                  -1000000000000 --> -16666666666:40
                1000000000000000 --> 16666666666666:40
               -1000000000000000 --> -16666666666666:40
                           1e+18 --> 16666666666666666:40
                          -1e+18 --> -16666666666666666:40
                           1e+20 --> 1666666666666666752:40
                          -1e+20 --> -1666666666666666752:40
                           1e+25 --> 166666666666666697424896:04
                          -1e+25 --> -166666666666666697424896:04
                           1e+30 --> 16666666666666666704873979904:16
                          -1e+30 --> -16666666666666666704873979904:16
                    128849018820 --> 2147483647:00
                   -128849018820 --> -2147483647:00
                    128849020054 --> 2147483667:34
                   -128849020054 --> -2147483667:34
           1.180591620717411e+21 --> 19676527011956854784:04
          -1.180591620717411e+21 --> -19676527011956854784:04
          1.797693134862316e+308 --> 2996155224770526471302168869341711813188863443303040828151933426890179148788615168103226874770040896498710950234612783266345520226229959458788332419124700807563385759480436831271585473539816641208848852443854529842024245861042631496840000693995654184204690418742185022600768539063077737531453954861570195456:08
         -1.797693134862316e+308 --> -2996155224770526471302168869341711813188863443303040828151933426890179148788615168103226874770040896498710950234612783266345520226229959458788332419124700807563385759480436831271585473539816641208848852443854529842024245861042631496840000693995654184204690418742185022600768539063077737531453954861570195456:08
                             inf --> inf
                            -inf --> -inf
                             nan --> nan
                             nan --> nan

答案 1 :(得分:1)

  

我想从一个双精度点上打印一个以分钟和秒为单位的时间,包括它们的小数部分,最多6位,并且不带尾随零。

具有挑战性的部分是将double转换为文本时发生的舍入。

以下代码将时间四舍五入为x.dddddd秒,然后重整秒数。

代码已针对边缘条件进行了测试。

#include <math.h>
#include <stdio.h>

int print_msf(double time_in_seconds, const char *suffix) {
  // print as seconds and a fraction - value rounded to nearest 0.000001
  //       -      308          1    . 000000  \0
  char buf[1 + (DBL_MAX_10_EXP + 1) + 1 + 6 + 1];
  sprintf(buf, "%.6f", time_in_seconds);
  int dp = '.'; // adjust for other locales if needed
  char *dpp = strchr(buf, dp);
  if (dpp == NULL) {
    return printf("%s%s\n", buf, suffix); // infinity or NaN
  } else {
    int significant_digs = 6;
    while (dpp[significant_digs] == '0') {
      significant_digs--;
    }
    dpp[1 + significant_digs] = '\0';
    *dpp = '\0';
    double t = atof(buf); // rounded whole number
    const char *sign = signbit(t) ? "-" : "";
    t = fabs(t);
    double seconds = fmod(t, 60);
    double minutes = (t - seconds) / 60;
    if (minutes) {
      seconds = fabs(seconds);
    }
    return printf("%s%.0f:%02.0f.%s%s\n", sign, minutes, seconds, dpp + 1,
        suffix);
  }
}

#include <float.h>
#include <limits.h>

int main(void) {
  //double time1 = 123.456789; //   2:03.456789 some text
  //double time2 = 12345.6;    // 205:45.6 some text
  double t[] = {123.456789, 12345.6, -0.0, 59.9999994, 59.9999996,
      (double) ULLONG_MAX * 64.0, DBL_MAX, 1.0 / 0.0, NAN};
  size_t n = sizeof t / sizeof t[0];
  for (size_t i = 0; i < n; i++) {
    printf("%30.16e --> ", t[i]);
    print_msf(t[i], " some text");
    printf("%30.16e --> ", -t[i]);
    print_msf(-t[i], " some text");
  }
  return 0;
}

输出

    1.2345678900000000e+02 --> 2:03.456789 some text
   -1.2345678900000000e+02 --> -2:03.456789 some text
    1.2345600000000000e+04 --> 205:45.6 some text
   -1.2345600000000000e+04 --> -205:45.6 some text
   -0.0000000000000000e+00 --> -0:00. some text
    0.0000000000000000e+00 --> 0:00. some text
    5.9999999400000000e+01 --> 0:59.999999 some text
   -5.9999999400000000e+01 --> -0:59.999999 some text
    5.9999999600000002e+01 --> 1:00. some text
   -5.9999999600000002e+01 --> -1:00. some text
    1.1805916207174113e+21 --> 19676527011956854784:04. some text
   -1.1805916207174113e+21 --> -19676527011956854784:04. some text
   1.7976931348623157e+308 --> 2996155224770526471302168869341711813188863000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:08. some text
  -1.7976931348623157e+308 --> -2996155224770526471302168869341711813188863000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:08. some text
                       inf --> inf some text
                      -inf --> -inf some text
                       nan --> nan some text
                      -nan --> -nan some text

答案 2 :(得分:-1)

这种方法使用堆栈而不是堆内存,因此它应该更快。

目标是快速代码,小占用空间和非常大的值无关紧要。 仅在非常罕见的圆角情况下,才需要更多的CPU周期。

它还可以与其他格式和其他printf()中的值组合。

新:格式的另一种解决方案:h:mm:ss.nnnnnn

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <math.h>

#define MAX_BUF_SZ 32
#ifndef DBL_MAX
#define DBL_MAX  1.7976931348623157e+308
#endif

static char *minutes_str(char *buf, double time) {
    const char *format = (time >= 0 ? "%d:%09.6f" : "-%d:%09.6f");
    time = (fabs(time) > INT_MAX * 60.0 ? INT_MAX * 60.0 : fabs(time));
    int len = snprintf(buf, MAX_BUF_SZ, format, (int)(time / 60), fmod(time, 60));
    if (len - 9 >= 0 && buf[len - 9] > '5') // correct rare rounding issue
        len = snprintf(buf, MAX_BUF_SZ, format, (int)(time / 60) + 1, .0);
    while (buf[--len] == '0'); // search trailing zeros or ...
    buf[len + (buf[len] != '.')] = '\0'; // dot and strip them
    return buf;
}

/**
 * Convenience macro. The return value should be used only directly in
 * function arguments but never stand-alone.
 */
#define time2minutestr(time) minutes_str((char[MAX_BUF_SZ]){'\0'}, time)

static char *hours_string(char *buf, double time)
{
    const char *format = (time >= 0 ? "%d:%02d:%09.6f" : "-%d:%02d:%09.6f");
    if (time == (double)NAN)
        printf("Invalid number\n");
    time = (fabs(time) > INT_MAX * 60.0 * 60.0 ? INT_MAX * 60.0 * 60.0 : fabs(time));
    int hours = time / 60 / 60, minutes = fmod(time / 60, 60);
    int len = snprintf(buf, MAX_BUF_SZ, format, hours, minutes, fmod(time, 60));
    if (len - 9 >= 0 && buf[len - 9] > '5') { // correct rare rounding issue
        if (++minutes > 59) {
            minutes = 0;
            hours++;
        }
        len = snprintf(buf, MAX_BUF_SZ, format, hours, minutes, .0);
    }
    while (buf[--len] == '0'); // search trailing zeros or ...
    buf[len + (buf[len] != '.')] = '\0'; // dot and strip them
    return buf;
}

/**
 * Convenience macro. The return value should be used only directly in
 * function arguments but never stand-alone.
 */
#define time2hourstr(time) hours_string((char[MAX_BUF_SZ]){'\0'}, time)

int main(int argc, char** argv)
{
    double a[] = {
        0, -1, 1, 59, 60, 61,
        121.1, 121.11, 121.111, 121.1111, 121.11111, 121.111111,
        12345.6,
        123.456789,
        129.9999994,
        129.9999995,
        599.9999994,
        599.9999995,
        599.99999951,
        599.9999999,
        23.9999999999,
        999.0000005, 1000.0000005, -999.0000005, -1000.0000005,
        999.9999999, -999.9999999,
        1e6, 1e12, 1e18,
        4321.0, -0.0, 59.9999994, 59.9999996,
        INT_MAX * 60.0, INT_MAX * 60.0 + 1234,
        -(INT_MAX + 1.0) * 60.0, -(INT_MAX + 1.0) * 60.0 - 1234,
        (double)ULLONG_MAX * 64.0, DBL_MAX, 1.0 / 0.0, (double)NAN,
    };
    size_t i;
    for (i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
        printf("%32.16g", a[i]);
        printf(" --> %s %s\n", time2minutestr(a[i]), "some text");
        printf("%32.16g", -a[i]);
        printf(" --> %s %s\n", time2minutestr(-a[i]), "some text");
    }
    printf("                                H A P P Y !\n");

    double b[] = {
        0, -1, 1, 59, 60, 61,
        12345.6,
        123.456789,
        3609.9999995,
        3609.99999951,
        359999.9999994,
        359999.9999995,
        359999.99999951,
        719999.9999995, 7199.9999999999,
        1e6, 1e12, 1e18,
        INT_MAX * 60.0, INT_MAX * 60.0 * 60.0,
        -(INT_MAX + 1.0) * 60.0, -(INT_MAX + 1.0) * 60.0 * 60.0,
        (double)ULLONG_MAX * 64.0, DBL_MAX, 1.0 / 0.0, (double)NAN,
    };
    for (i = 0; i < sizeof(b) / sizeof(b[0]); i++) {
        printf("%32.16g", b[i]);
        printf(" --> %s %s\n", time2hourstr(b[i]), "some other text");
        printf("%32.16g", -b[i]);
        printf(" --> %s %s\n", time2hourstr(-b[i]), "some other text");
    }
    printf("                            V E R Y   H A P P Y !\n");

    return (0);
}

输出:

                               0 --> 0:00 some text
                              -0 --> 0:00 some text
                              -1 --> -0:01 some text
                               1 --> 0:01 some text
                               1 --> 0:01 some text
                              -1 --> -0:01 some text
                              59 --> 0:59 some text
                             -59 --> -0:59 some text
                              60 --> 1:00 some text
                             -60 --> -1:00 some text
                              61 --> 1:01 some text
                             -61 --> -1:01 some text
                           121.1 --> 2:01.1 some text
                          -121.1 --> -2:01.1 some text
                          121.11 --> 2:01.11 some text
                         -121.11 --> -2:01.11 some text
                         121.111 --> 2:01.111 some text
                        -121.111 --> -2:01.111 some text
                        121.1111 --> 2:01.1111 some text
                       -121.1111 --> -2:01.1111 some text
                       121.11111 --> 2:01.11111 some text
                      -121.11111 --> -2:01.11111 some text
                      121.111111 --> 2:01.111111 some text
                     -121.111111 --> -2:01.111111 some text
                         12345.6 --> 205:45.6 some text
                        -12345.6 --> -205:45.6 some text
                      123.456789 --> 2:03.456789 some text
                     -123.456789 --> -2:03.456789 some text
                     129.9999994 --> 2:09.999999 some text
                    -129.9999994 --> -2:09.999999 some text
                     129.9999995 --> 2:10 some text
                    -129.9999995 --> -2:10 some text
                     599.9999994 --> 9:59.999999 some text
                    -599.9999994 --> -9:59.999999 some text
               599.9999994999999 --> 9:59.999999 some text
              -599.9999994999999 --> -9:59.999999 some text
                    599.99999951 --> 10:00 some text
                   -599.99999951 --> -10:00 some text
                     599.9999999 --> 10:00 some text
                    -599.9999999 --> -10:00 some text
                   23.9999999999 --> 0:24 some text
                  -23.9999999999 --> -0:24 some text
               999.0000005000001 --> 16:39.000001 some text
              -999.0000005000001 --> -16:39.000001 some text
                    1000.0000005 --> 16:40.000001 some text
                   -1000.0000005 --> -16:40.000001 some text
              -999.0000005000001 --> -16:39.000001 some text
               999.0000005000001 --> 16:39.000001 some text
                   -1000.0000005 --> -16:40.000001 some text
                    1000.0000005 --> 16:40.000001 some text
                     999.9999999 --> 16:40 some text
                    -999.9999999 --> -16:40 some text
                    -999.9999999 --> -16:40 some text
                     999.9999999 --> 16:40 some text
                         1000000 --> 16666:40 some text
                        -1000000 --> -16666:40 some text
                   1000000000000 --> 2147483647:00 some text
                  -1000000000000 --> -2147483647:00 some text
                           1e+18 --> 2147483647:00 some text
                          -1e+18 --> -2147483647:00 some text
                            4321 --> 72:01 some text
                           -4321 --> -72:01 some text
                              -0 --> 0:00 some text
                               0 --> 0:00 some text
                      59.9999994 --> 0:59.999999 some text
                     -59.9999994 --> -0:59.999999 some text
                      59.9999996 --> 1:00 some text
                     -59.9999996 --> -1:00 some text
                    128849018820 --> 2147483647:00 some text
                   -128849018820 --> -2147483647:00 some text
                    128849020054 --> 2147483647:00 some text
                   -128849020054 --> -2147483647:00 some text
                   -128849018880 --> -2147483647:00 some text
                    128849018880 --> 2147483647:00 some text
                   -128849020114 --> -2147483647:00 some text
                    128849020114 --> 2147483647:00 some text
           1.180591620717411e+21 --> 2147483647:00 some text
          -1.180591620717411e+21 --> -2147483647:00 some text
          1.797693134862316e+308 --> 2147483647:00 some text
         -1.797693134862316e+308 --> -2147483647:00 some text
                             inf --> 2147483647:00 some text
                            -inf --> -2147483647:00 some text
                             nan --> --2147483648:      nan some text
                            -nan --> --2147483648:      nan some text
                                H A P P Y !
                               0 --> 0:00:00 some other text
                              -0 --> 0:00:00 some other text
                              -1 --> -0:00:01 some other text
                               1 --> 0:00:01 some other text
                               1 --> 0:00:01 some other text
                              -1 --> -0:00:01 some other text
                              59 --> 0:00:59 some other text
                             -59 --> -0:00:59 some other text
                              60 --> 0:01:00 some other text
                             -60 --> -0:01:00 some other text
                              61 --> 0:01:01 some other text
                             -61 --> -0:01:01 some other text
                         12345.6 --> 3:25:45.6 some other text
                        -12345.6 --> -3:25:45.6 some other text
                      123.456789 --> 0:02:03.456789 some other text
                     -123.456789 --> -0:02:03.456789 some other text
                    3609.9999995 --> 1:00:09.999999 some other text
                   -3609.9999995 --> -1:00:09.999999 some other text
                   3609.99999951 --> 1:00:10 some other text
                  -3609.99999951 --> -1:00:10 some other text
                  359999.9999994 --> 99:59:59.999999 some other text
                 -359999.9999994 --> -99:59:59.999999 some other text
                  359999.9999995 --> 99:59:59.999999 some other text
                 -359999.9999995 --> -99:59:59.999999 some other text
                 359999.99999951 --> 100:00:00 some other text
                -359999.99999951 --> -100:00:00 some other text
                  719999.9999995 --> 199:59:59.999999 some other text
                 -719999.9999995 --> -199:59:59.999999 some other text
                 7199.9999999999 --> 2:00:00 some other text
                -7199.9999999999 --> -2:00:00 some other text
                         1000000 --> 277:46:40 some other text
                        -1000000 --> -277:46:40 some other text
                   1000000000000 --> 277777777:46:40 some other text
                  -1000000000000 --> -277777777:46:40 some other text
                           1e+18 --> 2147483647:00:00 some other text
                          -1e+18 --> -2147483647:00:00 some other text
                    128849018820 --> 35791394:07:00 some other text
                   -128849018820 --> -35791394:07:00 some other text
                   7730941129200 --> 2147483647:00:00 some other text
                  -7730941129200 --> -2147483647:00:00 some other text
                   -128849018880 --> -35791394:08:00 some other text
                    128849018880 --> 35791394:08:00 some other text
                  -7730941132800 --> -2147483647:00:00 some other text
                   7730941132800 --> 2147483647:00:00 some other text
           1.180591620717411e+21 --> 2147483647:00:00 some other text
          -1.180591620717411e+21 --> -2147483647:00:00 some other text
          1.797693134862316e+308 --> 2147483647:00:00 some other text
         -1.797693134862316e+308 --> -2147483647:00:00 some other text
                             inf --> 2147483647:00:00 some other text
                            -inf --> -2147483647:00:00 some other text
                             nan --> --2147483648:-2147483648:       some other text
                            -nan --> --2147483648:-2147483648:       some other text
                            V E R Y   H A P P Y !