序序我们都遇到过需要将整型时间按照一定格式显示的问题:如中文时间格式年-月-日 时:分:秒和英文时间格式MON/day Year hour:minute:second,或者是其它变化,如日期和时间不填0补齐和填0补齐等。
我们可以直接为每周时间输出格式准备一个输出函数,该输出函数基于format函数的格式来输出;但我们也需要一种通用的处理办法。
解决程序该程序基于标准函数实现,包含如下的头文件:
#include <time.h>
#include <iostream>
#include <strstream>
#include <string>
using namespace std;
转换函数封装到一个类中(当然可以不封装);我们定义了枚举变量Field来限定处理字段为6(年、月、日、时、分、秒)的最多处理能力。
算法的第1步是分解格式字符串的信息:把格式串每个关键字段的格式及其后缀字符记录下来,并把各字段出现的先后顺序记录到nOrder变量中。
算法的第2步是把整型时间转换为tm结构,然后依据各字段出现的先后顺序,按照其记录的个数和后缀,拼成一个字符串。
class DateGen
{
public:
//year, month, day, hour, minute, second
enum{FIELDS=6};
enum{YEAR, MONTH, DAY, HOUR, MINUTE, SECOND};
//Format string as following:
//YYYY-MM-DD hh:mm:ss
//among which character like 'Y' is key word,
//character like '-' is suffix.
//Count of key words varys from 1 to 4
bool getDate(time_t nTime, const string& strFormat, string& strOutput)
{
static char* pszMonthName[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
bool bRet = true;
int nOrder[FIELDS];
int index = -1;
m_nCurrField = -1;
strOutput = "";
for(int i = 0; i < strFormat.length(); i ++)
{
switch(strFormat[i])
{
case 'Y':modArray(index, YEAR, nOrder); break;
case 'M':modArray(index, MONTH, nOrder); break;
case 'D':modArray(index, DAY, nOrder); break;
case 'h':modArray(index, HOUR, nOrder); break;
case 'm':modArray(index, MINUTE, nOrder);break;
case 's':modArray(index, SECOND, nOrder); break;
default:
{
if(index >= 0)
{
m_field[index].strSuffix += strFormat[i]; break;
}
else
{
bRet = false;
//ignore
}
break;
}
}
}
struct tm* pTime = localtime(&nTime);
for(i = 0; i < FIELDS; i ++)
{
char szBuf[8];
memset(szBuf, 0, sizeof(szBuf));
int nVal = -1;
switch(nOrder[i])
{
case YEAR:nVal = 1900 + pTime->tm_year; break;
case MONTH:nVal = pTime->tm_mon + 1; break;
case DAY:nVal = pTime->tm_mday; break;
case HOUR:nVal = pTime->tm_hour; break;
case MINUTE:nVal = pTime->tm_min; break;
case SECOND:nVal = pTime->tm_sec; break;
}
if(MONTH == nOrder[i] && m_field[MONTH].nCount == 3)
{
strOutput += pszMonthName[nVal - 1];
}
else
{
ostrstream os(szBuf, sizeof(szBuf) - 1);
os.width(m_field[nOrder[i]].nCount);
os.fill('0');
os << nVal;
strOutput += os.str();
}
if(m_field[nOrder[i]].strSuffix.length() > 0)
{
strOutput += m_field[i].strSuffix;
}
}
return bRet;
}
void reset()
{
m_nCurrField = -1;
for(int i = 0; i < FIELDS; i ++)
{
m_field[i].nCount = 0;
m_field[i].strSuffix = "";
}
}
private:
void modArray(int& index, const int nField, int nOrder[])
{
if(m_nCurrField != nField)
{
m_nCurrField = nField;
index ++;
nOrder[index] = nField;
}
m_field[m_nCurrField].nCount ++;
}
typedef struct Field
{
int nCount;
string strSuffix;
Field():nCount(0), strSuffix(""){};
} Field;
Field m_field[FIELDS];
int m_nCurrField;
};
如下是一段使用代码,只是举例一下:
int main(int argc, char* argv[])
{
DateGen gen;
string strFormat = "YYYY-MM-DD hh::mm::ss";
string strOutput;
if(gen.getDate(time(NULL), strFormat, strOutput))
{
cout << "format:" << strFormat << endl;
cout << strOutput << endl;
}
gen.reset();
strFormat = "YYYY-MMM-DD hh::mm::ss";
if(gen.getDate(time(NULL), strFormat, strOutput))
{
cout << "format:" << strFormat << endl;
cout << strOutput << endl;
}
gen.reset();
strFormat = "MM/DD/YYYY hh:mm:ss";
if(gen.getDate(time(NULL), strFormat, strOutput))
{
cout << "format:" << strFormat << endl;
cout << strOutput << endl;
}
return 0;
}
为了反复使用该类,特别加入了reset函数,把原来记录的信息复位。
这里只是提供了一种思路,在ascii环境下能够使用,并没有考虑unicode的情况。