我已经编写了一个函数来将日期时间从一种格式转换为另一种格式-
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;julian day不起作用。
我在Solaris10上使用的是gcc,你知道我需要修改什么吗?
发布于 2010-08-03 14:25:33
更新
原始答案(如下)假定在输出(strftime)而不是输入(strptime)上使用"%y%j“格式。mktime函数将根据有效信息计算yday,但它不能以另一种方式工作。
如果你想解码这样的东西,你需要手动完成。下面是一些示例代码。它只进行了最少的测试,而且几乎肯定有bug。您可能需要更改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 2007年5月03日星期四08123 2008年5月02日星期五08124星期六
结束更新
在调用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;
}发布于 2010-08-03 12:30:26
检查strptime的预期行为,在某些实现中,它是贪婪的,并且会消耗尽可能多的数字。
这一直是我在MacOS上遇到的一个问题,在10.5中,随着UNIX标准遵从性的努力,实现发生了变化。在此之前,下面的调用运行良好。
strptime("20071124", "%Y%m%d")从10.5开始,您必须执行以下操作才能使其正常工作。
#define _NONSTD_SOURCE不过,您的编译库和操作系统可能有所不同。
发布于 2010-08-03 12:45:38
我可以告诉你问题出在哪里。当您将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设置这两个字段,这有点麻烦,但至少可以让您继续操作(也许您会找到更好的方法)。
我会在您的convert函数中插入对this的调用,并仅在特定情况下调用它,以免覆盖已设置的值:
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]而且,就像这里的所有代码一样,您应该彻底地测试它。我非常确定我得到了所有的边缘案例,但是,由于您没有为我的服务支付冷硬现金,您应该假设这只是一般建议,而不是特定的解决方案:-)
https://stackoverflow.com/questions/3393434
复制相似问题