【问题标题】:printf epochtime shows wrong valuesprintf epochtime 显示错误的值
【发布时间】:2021-02-14 05:38:05
【问题描述】:

我正在试验time_t 变量,这是有问题的代码:

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

struct tm epochtime;
time_t epochdate;

int main()
{
  epochtime.tm_mday = 19;
  epochtime.tm_mon = 10;
  epochtime.tm_year = 2002;
  epochtime.tm_hour = 0;
  epochtime.tm_min = 0;
  epochtime.tm_sec = 0 ;
  
  epochdate = mktime(&epochtime);

  printf("%ju\n",epochdate);
  printf("%ju\n", (uint32_t)epochdate);
  printf("%ju\n", (uint64_t)epochdate);
  printf("%ju\n", (uintmax_t)epochdate);
  printf("%Lf\n", epochdate);
  printf("%Le\n", epochdate);
}

我正在尝试打印给定日期的epochtime。代码可以编译并且没有错误,但是当我将打印的内容与我在this website 上计算的内容进行比较时,这些值并不相同。对于上面示例中的给定值,代码输出为:

210453397503
210453397503
18446744073709551615
18446744073709551615
-1.#QNAN0e+000
-1.#QNAN0e

虽然链接说该值应该是1034985600。我尝试了多个 printf 格式说明符,因为我在这里找到了有关如何打印 time_t 变量的多个答案,但它们似乎都不适合我。任何想法为什么?

【问题讨论】:

  • 18446744073709551615(uint64_t)-1 ... 显然你的 mktime() 正在返回 -1: C11 7.27.2.3 -- "如果无法表示日历时间,则函数返回值 (time_t )(-1)。”
  • 也许您需要将年份(1900 年前)和月份(1 个月前)移位,...并注意 DST?
  • 第一步应该始终是手册页:" tm_year 年份(当前年份减去 1900)。"
  • @pmg 这个月,我在计算时牢记 -1 转变。我查看了 struct tm 的确切定义,我没有指定那一年的链接是从 1900 年开始计算的。顺便说一句,你的建议奏效了,谢谢!
  • printf("%ju\n", (uint32_t)epochdate); 中,j 告诉 printf 你正在传递类型 uintmax_t 但你不是 - 它是 uint32_t 所以也是 未定义的行为 .请参阅Format specification syntax: printf

标签: c format-specifiers time-t


【解决方案1】:

我假设您想表示日期:2002 年 10 月 19 日 00:00:00,它对应于您期望的纪元时间戳:1034985600。

在这种情况下,你做错了。阅读the manual

故障时间存储在tm结构体中,在&lt;time.h&gt;中定义如下:

struct tm {
    int tm_sec;    /* Seconds (0-60) */
    int tm_min;    /* Minutes (0-59) */
    int tm_hour;   /* Hours (0-23) */
    int tm_mday;   /* Day of the month (1-31) */
    int tm_mon;    /* Month (0-11) */
    int tm_year;   /* Year - 1900 */
    int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
    int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
    int tm_isdst;  /* Daylight saving time */
};

你的年份应该是 2002 - 1900 = 102,你的月份应该是 9,而不是 10(月份从 0 开始 = 一月)。

正确的代码是:

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

int main(void) {
    struct tm epochtime = {
        .tm_mday = 19,
        .tm_mon = 9,
        .tm_year = 102,
        .tm_hour = 0,
        .tm_min = 0,
        .tm_sec = 0,
        .tm_isdst = -1
    };

    time_t epochdate = mktime(&epochtime);
    if (epochdate == (time_t)(-1)) {
        perror("mktime failed");
        return 1;
    }

    printf("%" PRIuMAX "\n", (uintmax_t)epochdate);
    return 0;
}

如您所愿正确输出1034985600

您的代码的问题很可能是 mktime 无法正确表示您提供的“错误”日期并返回 -1,然后您将其打印为无符号并变成一个巨大的无意义数字。

【讨论】:

    【解决方案2】:

    printf epochtime 显示错误的值

    没有为time_t 指定匹配的打印说明符。除了printf("%ju\n", (uintmax_t)epochdate); 之外的所有printf() 都可能导致未定义的行为 (UB)。

    ...这里有多个关于如何打印 time-t 变量的答案,但它们似乎都不适合我。任何想法为什么?

    time_t 是一种能够表示时间的类型。

    clock_ttime_t 中可表示的时间范围和精度是实现定义的。 C17dr § 7.27.1 4


    使用演员表打印。由于time_t 通常是非常 有符号整数类型,因此转换为宽有符号 类型:

    time_t t;
    time(&t);
    printf("%jd", (intmax_t) t);
    // or pre-C99
    printf("%ld", (long) t);
    

    或者为了广泛的可移植性而损失一些精度的风险很小,

    printf("%f", (double) t);
    

    printf("%ju\n", (uintmax_t)epochdate); --> 18446744073709551615 肯定是mktime(&amp;epochtime); 由于转换错误返回-1 的结果,可能是由于epochtime.tm_year = 2002; 的范围错误。 .tm_year 1900 年的年份。@pmg

    最好先将 epochtime 清零以初始化所有成员 - 可能超过 9 个。

    struct tm epochtime = {0};
    epochtime.tm_mday = 19;
    epochtime.tm_mon = 10 - 1;       // Months since January
    epochtime.tm_year = 2002 - 1900; // Year since 1900
    epochtime.tm_isdst = -1;         // Let system daylight daylight time for that date
    epochdate = mktime(&epochtime);  // epochtime is assumed here to be a local time
    

    【讨论】:

    • tm_isdst 无论如何都由mktime 设置。
    • @MarcoBonelli struct tm 的所有成员都可以由mktime() 设置以将它们带入主要范围。将.tm_isdst 初始化为零(如您的回答)强制mktime()epochtime 评估为标准时间 - 即使在夏天也是如此。将其设置为 -1,允许 mktime()epochtime 评估为具有夏季时间戳的夏令时,之后,该成员设置为 0,1。
    猜你喜欢
    • 2016-07-08
    • 2018-01-28
    • 2019-11-16
    • 1970-01-01
    • 2020-02-10
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    相关资源
    最近更新 更多