strptime() 在 C 中产生垃圾时间
strptime() produces junk times in C
我尝试使用 strptime() 来解析 ISO 8601 格式的日期(由“%F”或“%Y-%m-%d”指定),但是当我从结果结构 tm 中读取时,我得到时间、分钟和秒的荒谬值。
这是一个示例代码和结果:
char *s_date = (char *)malloc(sizeof(char) * 255);
scanf("%s", s_date);
struct tm bd_date;
strptime(s_date, "%Y-%m-%d", &bd_date)
printf("%d-%d-%d %d:%d:%d\n", (bd_date.tm_year + 1900), (bd_date.tm_mon + 1), bd_date.tm_mday, bd_date.tm_hour, bd_date.tm_min, bd_date.tm_sec);
输入“1990-05-01”的结果输出是:
1990-5-1 2007659173:32766:1076394855,显示 tm_hour、tm_min 和 tm_sec 的非法值。
我究竟做错了什么?有什么我想念的吗?我虽然 strptime() 会自动将格式中未使用的字段设置为 0,但似乎并非如此。
您可能需要在自己调用 strptime
之前将所有字段设置为零。注意 struct tm bd_date;
是在栈上分配的,所以此时 bd_date 充满了垃圾(随机值),而不是充满了零。
strptime
函数将只设置格式字符串中指定的字段。来自 man page:
In principle, this function does not initialize tm but only stores the
values specified. This means that tm should be initialized before the
call. Details differ a bit between different UNIX systems. The glibc
implementation does not touch those fields which are not explicitly
specified, except that it recomputes the tm_wday and tm_yday field if
any of the year, month, or day elements changed.
因此在您的情况下,由于仅指定了年、月和日,因此仅设置了那些相应的字段(以及星期几和一年中的某一天)。
Apple 的 strptime
手册页明确指出:
If the <i>format</i>
string does not contain enough conversion specifications to completely specify the resulting <i>struct tm
, the unspecified members of <i>timeptr
are left untouched. For example, if format is “%H:%M:%S
”, only <i>tm_hour
, <i>tm_sec
and <i>tm_min
will be modified.
Linux man pages 没有那么明确,但与此一致:
In principle, this function does not initialize <i>tm
but stores only the values specified. This means that <i>tm
should be initialized before the call.
POSIX 标准,苹果的 macOS 和 Linux 都试图符合,在我手头的 2008 版本中既没有上述也没有类似的文字。根本不关心其他结构体成员是否被修改或结构体是否被初始化
因此,至少在某些实现中,strptime
不会修改格式字符串中没有相应描述符的成员。例如,如果没有 hour 的描述符,例如 %H
,它不会修改结构的 hour 成员。如果你想设置这些成员,你可以在调用 strptime
.
之前设置它们
我尝试使用 strptime() 来解析 ISO 8601 格式的日期(由“%F”或“%Y-%m-%d”指定),但是当我从结果结构 tm 中读取时,我得到时间、分钟和秒的荒谬值。 这是一个示例代码和结果:
char *s_date = (char *)malloc(sizeof(char) * 255);
scanf("%s", s_date);
struct tm bd_date;
strptime(s_date, "%Y-%m-%d", &bd_date)
printf("%d-%d-%d %d:%d:%d\n", (bd_date.tm_year + 1900), (bd_date.tm_mon + 1), bd_date.tm_mday, bd_date.tm_hour, bd_date.tm_min, bd_date.tm_sec);
输入“1990-05-01”的结果输出是: 1990-5-1 2007659173:32766:1076394855,显示 tm_hour、tm_min 和 tm_sec 的非法值。 我究竟做错了什么?有什么我想念的吗?我虽然 strptime() 会自动将格式中未使用的字段设置为 0,但似乎并非如此。
您可能需要在自己调用 strptime
之前将所有字段设置为零。注意 struct tm bd_date;
是在栈上分配的,所以此时 bd_date 充满了垃圾(随机值),而不是充满了零。
strptime
函数将只设置格式字符串中指定的字段。来自 man page:
In principle, this function does not initialize tm but only stores the values specified. This means that tm should be initialized before the call. Details differ a bit between different UNIX systems. The glibc implementation does not touch those fields which are not explicitly specified, except that it recomputes the tm_wday and tm_yday field if any of the year, month, or day elements changed.
因此在您的情况下,由于仅指定了年、月和日,因此仅设置了那些相应的字段(以及星期几和一年中的某一天)。
Apple 的 strptime
手册页明确指出:
If the
<i>format</i>
string does not contain enough conversion specifications to completely specify the resulting<i>struct tm
, the unspecified members of<i>timeptr
are left untouched. For example, if format is “%H:%M:%S
”, only<i>tm_hour
,<i>tm_sec
and<i>tm_min
will be modified.
Linux man pages 没有那么明确,但与此一致:
In principle, this function does not initialize
<i>tm
but stores only the values specified. This means that<i>tm
should be initialized before the call.
POSIX 标准,苹果的 macOS 和 Linux 都试图符合,在我手头的 2008 版本中既没有上述也没有类似的文字。根本不关心其他结构体成员是否被修改或结构体是否被初始化
因此,至少在某些实现中,strptime
不会修改格式字符串中没有相应描述符的成员。例如,如果没有 hour 的描述符,例如 %H
,它不会修改结构的 hour 成员。如果你想设置这些成员,你可以在调用 strptime
.