我编写了一个将日期时间从一种格式转换为另一种格式的函数 -
int convertDateTime(char* source_fmt,char* dest_fmt,char* source,char* dest)
{
struct tm tmpptr;
if (strptime(source,source_fmt,&tmpptr) == NULL)
{
strcpy(dest,"");
return -1;
}
strftime(dest,100,dest_fmt,&tmpptr);
return 0;
}
它适用于大多数格式,但当我使用format =“%y%j”时,我得到的只是10001;朱利安日不起作用。
我在solaris 10上使用gcc。知道我需要改变什么吗?
答案 0 :(得分:0)
检查strptime的预期行为,在某些实现中它是贪婪的并且会消耗尽可能多的数字。
对于我来说,这对MacOS来说是一个问题,10.5的实现在UNIX标准合规性方面有所改变。在此之前,以下调用工作正常。
strptime("20071124", "%Y%m%d")
从10.5开始,您必须执行以下操作才能使其正常工作。
#define _NONSTD_SOURCE
您的编译器库和操作系统可能会有所不同。
答案 1 :(得分:0)
我可以告诉你问题是什么。当您使用strptime()
格式的%j
时,它只会填充tm_yday
上的struct tm
字段。顺便说一下,这不仅限于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_mday
重建tm_mon
和tm_yday
。
但是,如果您遇到解决方案,请尝试一下:
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
来设置这两个字段,而且它有点像kludge,但至少可以帮助你(也许你会找到更好的方法)。
我会在你的转换函数中插入一个调用,并且只在特定情况下调用它,以免覆盖已设置的值:
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]
而且,就像这里的所有代码一样,你应该彻底测试它。我很确定我得到了所有优势,但是,既然你没有向我支付冷硬现金用于我的服务,你应该假设这只是一般建议,而不是特定的解决方案: - )
答案 2 :(得分:-1)
<强>更新强>
原始答案(下面)假定在输出(strftime)上使用“%y%j”格式而不是输入(strptime)。 mktime函数将根据有效信息计算yday,但它不会以其他方式工作。
如果你想解码那样的东西,你需要手动完成。下面是一些示例代码。它的测试很少,几乎肯定有错误。您可能需要根据所需的输入格式更改ir。
#include <string>
#include <ctime>
#include <cassert>
#include <iostream>
int GetCurrentYear()
{
time_t tNow(::time(NULL));
struct tm tmBuff = *::localtime(&tNow);
return tmBuff.tm_year;
}
bool IsLeapYear(int nYear)
{
if (0 == (nYear%1000)) return true;
if (0 == (nYear%100)) return false;
if (0 == (nYear%4)) return true;
return false;
}
// nMonth = 0 (Jan) to 11 (Dec)
int DaysPerMonth(int nMonth, bool bLeapYear)
{
// J F M A M J J A S O N D
int nDays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
assert(nMonth>=0 && nMonth<12);
int nRet = nDays[nMonth];
if (bLeapYear && nMonth==1)
nRet++;
return nRet;
}
// sDate is in the format YYDDD where YY is the last 2 digits of the year
// and YYY is the day of the year (1/1 = 1, 31/12 = 365 for non-leap year)
bool DecodeDate(const std::string &sDate, struct tm &tmBuff)
{
if (sDate.length() != 5 ||
!isdigit(sDate[0]) ||
!isdigit(sDate[1]) ||
!isdigit(sDate[2]) ||
!isdigit(sDate[3]) ||
!isdigit(sDate[4]))
{
return false;
}
::memset(&tmBuff, 0, sizeof(struct tm));
tmBuff.tm_year = GetCurrentYear();
// drop last 2 digits
tmBuff.tm_year -= tmBuff.tm_year%100;
// replace last 2 digits
tmBuff.tm_year += ::atoi(sDate.substr(0, 2).c_str());
tmBuff.tm_yday = ::atoi(sDate.substr(2).c_str());
int nDays(tmBuff.tm_yday);
bool bLeapYear(IsLeapYear(1900 + tmBuff.tm_year));
int nTmp = DaysPerMonth(0, bLeapYear);
while (nTmp < nDays)
{
nDays -= nTmp;
tmBuff.tm_mon++;
nTmp = DaysPerMonth(tmBuff.tm_mon, bLeapYear);
}
tmBuff.tm_mday = nDays;
::mktime(&tmBuff);
return true;
}
int main(int argc, char *argv[])
{
for (int i=1; i<argc; i++)
{
struct tm tmBuff;
DecodeDate(argv[i], tmBuff);
const size_t nSize(128);
char szBuff[nSize];
strftime(szBuff, nSize, "%A, %d %B %Y", &tmBuff);
std::cout << argv[i] << '\t' << szBuff << std::endl;
}
return 0;
}
=============================================== =
C:\Dvl\Tmp>Test.exe 07123 08123 08124 07123 Thursday, 03 May 2007 08123 Friday, 02 May 2008 08124 Saturday, 03 May 2008
结束更新
在调用strptime()之后,调用mktime(),它将填充结构中任何缺少的成员。此外,您应该在开始之前将结构清零。
#include <string>
#include <ctime>
int convertDateTime(const std::string &sSourceFmt,
const std::string &sDestFmt,
const std::string &sSource,
std::string &sDest)
{
struct tm tmbuff = { 0 };
if (::strptime(sSource.c_str(), sSourceFmt.c_str(), &tmbuff) != NULL)
{
::mktime(&tmbuff);
const size_t nSize(256);
char szBuff[nSize+1] = "";
if (::strftime(szBuff, nSize, sDestFmt.c_str(), &tmbuff))
{
sDest = szBuff;
return 0;
}
}
sDest.clear();
return -1;
}