我可以告訴你問題是什麼。當您使用strptime()
和%j
格式時,它只填充struct tm
上的tm_yday
字段。順便說一下,這不僅限於Solaris,CygWin gcc也在做同樣的事情。
因爲你strftime()
是最有可能使用的其他領域(tm_mon
和tm_mday
),而這些仍然設置爲零,這就是爲什麼你得到一年的錯誤的一天。
下面的代碼說明了這一點:
#include <time.h>
#include <stdio.h>
#include <string.h>
#define dump() \
printf ("DEBUG tm_sec = %d, tm_min = %d, tm_hour = %d, tm_mday = %d, " \
"tm_mon = %d, tm_year = %d, tm_wday = %d, tm_yday = %d, " \
"tm_isdst = %d\n", \
tmpptr.tm_sec, tmpptr.tm_min, tmpptr.tm_hour, tmpptr.tm_mday, \
tmpptr.tm_mon, tmpptr.tm_year, tmpptr.tm_wday, tmpptr.tm_yday, \
tmpptr.tm_isdst)
int convertDateTime(char* source_fmt,char* dest_fmt,char* source,char* dest) {
struct tm tmpptr;
memset (&tmpptr,0,sizeof(tmpptr));
dump();
if (strptime(source,source_fmt,&tmpptr) == NULL) {
strcpy(dest,"");
return -1;
}
dump();
strftime(dest,100,dest_fmt,&tmpptr);
return 0;
}
int main (int argc, char *argv[]) {
char dest[1000];
printf ("1: [%s]\n", argv[1]);
printf ("2: [%s]\n", argv[2]);
printf ("3: [%s]\n", argv[3]);
printf ("retval = %d\n", convertDateTime (argv[1],argv[2],argv[3],dest));
printf ("=: [%s]\n", dest);
return 0;
}
當你這樣運行:
pax> date ; ./tetsprog %y%j %Y-%m-%d 10162
你:
Tue Aug 3 12:46:13 WAST 2010
1: [%y%j]
2: [%Y-%m-%d]
3: [10162]
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 0, tm_mon = 0, tm_year = 0,
tm_wday = 0, tm_yday = 0, tm_isdst = 0
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 0, tm_mon = 0, tm_year = 110,
tm_wday = 0, tm_yday = 161, tm_isdst = 0
retval = 0
=: [2010-01-00]
修復它是棘手的,我沒有意識到任何標準的時間函數將會重建從tm_yday
獲得tm_mday
和tm_mon
。
但是,如果你堅持一個解決方案,嘗試了這一點:
static void fixIt (struct tm *t) {
static int monthDaysN[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static int monthDaysL[] = {31,29,31,30,31,30,31,31,30,31,30,31};
int *monthDays = monthDaysN;
int base = 0;
int i;
if (((t->tm_year + 1900) % 4) == 0) monthDays = monthDaysL;
if (((t->tm_year + 1900) % 100) == 0) monthDays = monthDaysN;
if (((t->tm_year + 1900) % 400) == 0) monthDays = monthDaysL;
// Leap years irrelevant for January dates.
if (t->tm_yday < 31) monthDays = monthDaysN;
for (i = 0; i < 12; i++) {
if (t->tm_yday - base < monthDays[i]) {
t->tm_mday = t->tm_yday - base + 1;
t->tm_mon = i;
return;
}
base += monthDays[i];
}
}
它將爲基於tm_year
和tm_yday
這兩個領域,這是一個有點雜牌的,但將讓你在去最少(也許你會找到更好的方法)。
我會插入到該呼叫在您的轉換功能,只把它在特定環境下,以免覆蓋已設置的值:
int convertDateTime(char* source_fmt,char* dest_fmt,char* source,char* dest) {
struct tm tmpptr;
memset (&tmpptr,0,sizeof(tmpptr));
dump();
if (strptime(source,source_fmt,&tmpptr) == NULL) {
strcpy(dest,"");
return -1;
}
if ((tmpptr.tm_yday != 0) && (tmpptr.tm_mday == 0))
fixIt (&tmpptr);
dump();
strftime(dest,100,dest_fmt,&tmpptr);
return 0;
}
這給:
pax> date ; testprog %y%j %Y-%m-%d 10162
Tue Aug 3 13:34:36 WAST 2010
1: [%y%j]
2: [%Y-%m-%d]
3: [10162]
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 0, tm_mon = 0, tm_year = 0,
tm_wday = 0, tm_yday = 0, tm_isdst = 0
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 11, tm_mon = 5, tm_year = 110,
tm_wday = 0, tm_yday = 161, tm_isdst = 0
retval = 0
=: [2010-06-11]
而且,像這裏的所有代碼一樣,您應該對其進行徹底測試。我很確定我得到了所有的邊緣情況,但是,既然你沒有爲我的服務付給我冷硬的現金,你應該認爲這只是一般性建議,而不是一個具體的解決方案:-)
謝謝!這完美的作品! – vineet 2010-08-03 07:12:47
我真的很驚訝的作品。它不在Cygwin gcc下,只有tm_year和tm_yday被設置,事實上,你引用的doco聲明「timeptr結構的tm_wday和tm_yday組件的原始值被忽略」。但是,如果OP說沒關係,我猜沒關係:-) – paxdiablo 2010-08-03 07:28:36
實際上,_still_在CygWin下不起作用,glibc 2.9的源代碼在其計算中似乎沒有使用tm_yday,所以我仍然不服氣。你可以用'%y%j'的輸入格式,輸入值'10032'和輸出格式'%Y-%m-%d'來試試它,看看它做了什麼? – paxdiablo 2010-08-03 09:18:42