【问题标题】:baffled by output result from strftime()对 strftime() 的输出结果感到困惑
【发布时间】:2013-10-12 00:50:51
【问题描述】:

仔细查看time.h几次后,我写了以下func:

void output_date ( int day, int month, int year ) {
    char buffer[64] = "";
    struct tm *e_time = calloc( (size_t) 1, sizeof(struct tm) );

    e_time->tm_year = year - 1900;
    e_time->tm_mon = month - 1;
    e_time->tm_mday = day;
    e_time->tm_hour = 0;
    e_time->tm_min = 0;
    e_time->tm_sec = 0;
    e_time->tm_isdst = -1;

    /* strftime ( buffer, 64, (char *)0, e_time ); */
    strftime ( buffer, 64, "%a %b %e %H:%M:%S %Z (%z) %Y", e_time );

    printf ( "%s\n", buffer );

    free(e_time);
    e_time = NULL;

}

然后我用一系列可能的输入调用了这个函数,但什么也没看到 像这样的奇怪输出:

Sun Jul  8 00:00:00  () 2013
Sun Jul  9 00:00:00  () 2013
Sun Jul 10 00:00:00  () 2013
Sun Jul 11 00:00:00  () 2013
Sun Jul 12 00:00:00  () 2013

当我将格式字符串测试为 strftime 时,我看到了很好的结果:

$ date -u "+%a %b %e %H:%M:%S %Z (%z) %Y"
Sat Oct 12 00:40:05 GMT (+0000) 2013

我什至通过调试器单步执行并看到了相同的结果 奇怪的结果:

stopped in main at line 27 in file "flight.c"
   27                       output_date ( day+1, month+1, year );
(dbx) print day+1, month+1, year
day+1 = 1
month+1 = 1
year = 1977

(dbx) step                      
stopped in output_date at line 43 in file "flight.c"
   43       char buffer[64] = "";
(dbx) step
stopped in output_date at line 44 in file "flight.c"
   44       struct tm *e_time = calloc( (size_t) 1, sizeof(struct tm) );
(dbx) step
stopped in output_date at line 46 in file "flight.c"
   46       e_time->tm_year = year - 1900;
(dbx) print e_time
e_time = 0x100101640
(dbx) step        
stopped in output_date at line 47 in file "flight.c"
   47       e_time->tm_mon = month - 1;
(dbx) step
stopped in output_date at line 48 in file "flight.c"
   48       e_time->tm_mday = day;
(dbx) step
stopped in output_date at line 49 in file "flight.c"
   49       e_time->tm_hour = 0;
(dbx) step
stopped in output_date at line 50 in file "flight.c"
   50       e_time->tm_min = 0;
(dbx) step
stopped in output_date at line 51 in file "flight.c"
   51       e_time->tm_sec = 0;
(dbx) step
stopped in output_date at line 52 in file "flight.c"
   52       e_time->tm_isdst = -1;
(dbx) step
stopped in output_date at line 55 in file "flight.c"
   55       strftime ( buffer, 64, "%a %b %e %H:%M:%S %Z (%z) %Y", e_time );
(dbx) print *e_time
*e_time = {
    tm_sec   = 0
    tm_min   = 0
    tm_hour  = 0
    tm_mday  = 1
    tm_mon   = 0
    tm_year  = 77
    tm_wday  = 0
    tm_yday  = 0
    tm_isdst = -1
}
(dbx) step        
stopped in output_date at line 57 in file "flight.c"
   57       printf ( "%s\n", buffer );
(dbx) print buffer
buffer = "Sun Jan  1 00:00:00  () 1977"
(dbx) quit    

事实上,我所得到的只是一周中的某一天是星期天和正确的月份 正确的日期和年份。似乎没有什么是正确的。

我是否遗漏了一些明显的东西?

【问题讨论】:

  • 什么编译器和操作系统?
  • 到目前为止,我已经尝试了带有 gcc 4.7.2 的 Debian Linux 7.1 以及带有 Oracle Studio 12 的 Solaris 10。在 Solaris 上,我看到了上述结果。在 Linux 上,我得到一个段错误。抱歉..遇到了段错误...现在我得到了一个奇怪的结果。
  • 它在 ideone.com 上也有段错误...
  • 仅供参考...ideone.com/QpUguN 是对 ideone 的测试。另外,请查看 ideone 代码。无需像您在这里所做的那样致电callocfree。你在白白浪费时间。在e_time 上调用memset 足以避免段错误,但不会使输出完整。
  • 只是想帮忙...`事实上,我可以在堆上使用一个普通变量。` %s/heap/stack/

标签: c date time


【解决方案1】:

您为字段tm_isdst 提供了-1 的值,这意味着夏令时不可用,如果夏令时有效,则将其更改为1,否则将其更改为0

正如@Paul Griffiths 指出的那样,在这里调用mktime(e_time) 是更好的选择,mktime 函数将填充分解的e_time,因为它还将修复tm_wdaytm_day 之类的文件.对于tm_isdst的字段,遵循如下规则:

tm_isdst 的正值或零值导致mktime 函数最初分别假定夏令时在指定时间内有效或无效。负值会导致它尝试确定夏令时是否在指定时间内有效。

【讨论】:

  • -1 也意味着mktime() 应该尝试发现 DST 是否生效,这通常是您想要做的。
  • @PaulGriffiths 是的,我已经添加了那部分,这是一个更好的解决方案。如果该信息可用,手动修复 tm_isdst 也可以。
  • 在这种情况下,当他试图打印出星期几和时区信息时,我不会指望手动设置 tm_isdst 就足够了,而无需调用 mktime() 并留下像 @ 这样的成员987654338@ 未初始化(或设置为0,在这种情况下,由于calloc() 调用,这就是它一直显示星期日的原因)。
  • @paullanken 在这种情况下,mktime 就是您所需要的。我引用的词来自 C 标准,也许你应该检查一下。
  • @PaulGriffiths 你说得对,mktime 是这里更好的选择。
【解决方案2】:

您应该在填充结构之后调用mktime(e_time),但在调用strftime() 之前。您还有一些其他结构成员当前尚未完成。传递具有未初始化值的结构(或初始化为不正确的值,在这里,由于您的calloc() 调用)通常是一件坏事,mktime() 会修改您传递的结构来为您填充它们。

像这样:

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

void output_date ( int day, int month, int year ) {
    char buffer[64] = "";
    struct tm *e_time = calloc( (size_t) 1, sizeof(struct tm) );

    e_time->tm_year = year - 1900;
    e_time->tm_mon = month - 1;
    e_time->tm_mday = day;
    e_time->tm_hour = 0;
    e_time->tm_min = 0;
    e_time->tm_sec = 0;
    e_time->tm_isdst = -1;

    if ( mktime(e_time) < 0 ) {
        fprintf(stderr, "Error getting calendar time.\n");
        exit(EXIT_FAILURE);
    }

    int n = strftime ( buffer, 64, "%a %b %e %H:%M:%S %Z (%z) %Y", e_time );
    printf("Return from strftime() is %d\n", n);

    printf ( "%s\n", buffer );

    free(e_time);
    e_time = NULL;

}

int main(void) {
    output_date(12, 6, 2013);
    return 0;
}

产量:

paul@local:~/src/c/scratch$ ./st
Return from strftime() is 36
Wed Jun 12 00:00:00 EDT (-0400) 2013
paul@local:~/src/c/scratch$

【讨论】:

  • 哇!我刚刚检查了 mktime 上的联机帮助页,它看起来返回了一个 time_t 类型的对象。抱歉,不是对象,而是数据类型。此外,似乎做了一些很酷的事情。好的..让我试试那个好先生!
  • @paullanken:是的,确实如此,但在你的情况下,你不需要使用它,除了检查你总是应该的回报。这里的关键是mktime() 修改了您传递给它的struct tm
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多