生成UNIX时间戳超出C中传递的日期时间

生成UNIX时间戳超出C中传递的日期时间,c,datetime,timestamp,redhat,time-t,C,Datetime,Timestamp,Redhat,Time T,我正在将一个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; }

我正在将一个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时间戳out-datetime作为字符串传入

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年-知道为什么吗?

TL;博士:

在将tm传递给API之前,您需要初始化它:

memset(&tm, 0, sizeof tm);
为什么?

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

$ man strptime
返回值 函数的返回值是指向第一个字符的指针 未在此函数调用中处理。如果输入字符串包含 超过返回值格式字符串所需的字符数 在最后一个使用的输入字符后面的点。万一 整个输入字符串被消耗,返回值指向空字节 在字符串的末尾。如果strtime无法匹配所有的for- mat字符串,因此函数返回NULL时出错

注释

原则上,此函数不初始化tm,只存储 指定的值。这意味着tm应该被初始化 在电话之前。不同UNIX之间的详细信息略有不同 系统。glibc实现不涉及以下字段: 未明确指定,除非它重新计算tm_wday 和tm_yday字段(如果年、月或日元素发生任何更改)

因此,由于tm未设置为0,某些字段可能包含随机值

此外:

$ man mktime
mktime函数将tm结构的字段修改为 以下为:tm_wday和 tm_yday设置为根据其他字段的内容确定的值;if结构 如果成员超出其有效间隔,则将对其进行规范化,例如,40 10月改为11月9日;tm_isdst的设置与初始值为a无关 分别为正值或0,以指示DST是否在 指定时间。调用mktime也会设置外部变量tzname,其中包含信息 关于当前时区

随机值可能超出范围,mktime尝试将其正常化。
虽然它做得很好,但这一年却暴露了这一点

非常感谢,这确实解决了问题虽然解决方案是绝对正确的,但您可以在Notes中添加手册页中的引号,这可能解释了OP的问题:原则上,此函数不初始化tm,而只存储指定的值。这意味着tm应该在调用之前初始化。建议显示如何将tm设置为0。由于struct-tm可能有普通9以外的字段,所以执行memset&tm、0、sizeof-tm或struct-tm={0}之类的操作是很好的。我见过太多的代码示例,其中9个缺失的tm_isdst中只有6个被初始化,这导致了UB。