1

我正在将一个 C 应用程序从 Solaris 移植到 RedHat,而这个功能在 RedHat 上不能很好地工作(我需要你的帮助来确定原因):

int toTimestamp (const char *InputDate, const char *DateFormat, time_t *lTimestamp){
    struct tm tm;

    if (NULL == strptime(InputDate, DateFormat, &tm)){
        return FALSE;
    }
    *lTimestamp = mktime(&tm);
    return TRUE;    
}

基本上,它以指定格式从作为字符串传入的日期时间生成 UNIX 时间戳。

char *effPaymentDate = NULL;
char *CohDueDate = NULL;
//...
effPaymentDate = PayRec->RecDate;//char RecDate[8+1];, value 20141005
CohDueDate = PayRec->DueDate;//char DueDate[8+1];, value 20140820

time_t currentDateUNIX;
time_t DueDateUNIX;
if (FALSE == toTimestamp(CohDueDate, "%Y%m%d", &DueDateUNIX) ||
     FALSE == toTimestamp(effPaymentDate, "%Y%m%d", &currentDateUNIX)) {
  return NULL;
}
//...

但是,它似乎无法正常工作(对于 effPaymentDate 可以正常工作,为 CohDueDate 提供错误的日期 - 即 2543 年) - 任何想法为什么?

4

1 回答 1

0

TL;博士:

您需要tm在将其传递给 API 之前进行初始化:

memset(&tm, 0, sizeof tm);

为什么 ?

strptime可能会在您没有注意到的情况下失败:

$ man strptime

返回
值 函数的返回值是一个指针,指向该函数调用中未处理的第一个字符。如果输入字符串包含的字符多于格式字符串所需的字符,则返回值指向最后一个使用的输入字符之后。如果使用整个输入字符串,则返回值指向字符串末尾的空字节。如果 strptime() 未能匹配所有格式字符串并因此发生错误,该函数将返回 NULL。

笔记

原则上,此函数不会初始化 tm,而仅存储指定的值。这意味着 tm 应该在调用之前初始化。不同 UNIX 系统之间的细节略有不同。glibc 实现不会触及那些未明确指定的字段,除非它在年、月或日元素中的任何一个发生更改时重新计算 tm_wday 和 tm_yday 字段。

所以因为tm没有设置为0,一些字段可能包含随机值。

而且:

$ man mktime

mktime() 函数对 tm 结构的字段进行如下修改: tm_wday 和 tm_yday 设置为根据其他字段的内容确定的值;如果结构成员超出其有效区间,它们将被标准化(例如,10 月 40 日变为 11 月 9 日);tm_isdst 分别设置(不管其初始值)为正值或 0,以指示 DST 在指定时间是否有效。调用 mktime() 还会使用有关当前时区的信息设置外部变量 tzname。

随机值可能超出范围,并mktime尝试对其进行归一化。虽然做得很好,但year背叛了它!

于 2015-02-20T15:23:40.817 回答