I'm porting a C app from Solaris to RedHat, and this function does not work very well on RedHat (and I need your help determing why):
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;
}
Basically, it produces UNIX timestamp out of datetime passed in as a string, with specified format.
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", ¤tDateUNIX)) {
return NULL;
}
//...
However, it does not seem to work correctly (works OK for effPaymentDate, gives wrong dates for CohDueDate - i.e. year 2543) - any ideas why?
TL;DR:
You need to initialize tm
before passing it to APIs:
memset(&tm, 0, sizeof tm);
Why ?
strptime
might fail without you noticed it:
$ man strptime
RETURN VALUE
The return value of the function is a pointer to the first character not processed in this function call. In case the input string contains more characters than required by the format string the return value points right after the last consumed input character. In case the whole input string is consumed the return value points to the null byte at the end of the string. If strptime() fails to match all of the for‐ mat string and therefore an error occurred the function returns NULL.NOTES
In principle, this function does not initialize tm but stores only 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.
So because tm
is not set to 0, some fields may contain random values.
Moreover:
$ man mktime
The mktime() function modifies the fields of the tm structure as follows: tm_wday and tm_yday are set to values determined from the contents of the other fields; if structure members are outside their valid interval, they will be normalized (so that, for example, 40 October is changed into 9 November); tm_isdst is set (regardless of its initial value) to a positive value or to 0, respectively, to indicate whether DST is or is not in effect at the specified time. Calling mktime() also sets the external variable tzname with information about the current timezone.
The random values are likely to be out of range, and mktime
tries to normalize it.
It did a good job though, but the year
betrayed it !