关于CTime::Format在Unicode下的输出问题及解决办法
旧有程序,在处理CTime的格式化时,经常会使用Format函数进行输出。
普通情况下不会有问题。但最近改Bug,在旧控件中碰到一个特殊情况,发现其缺陷。
[具体状况]
用MFC编写的OCX中,有如下简单代码:
CTime t = CTime::GetCurrentTime();
CString sTime = t.Format(_T("最近计算时间: %Y,%m,%d %H:%M:%S"));
ANSI版下,上述代码执行正常,但如果是Unicode版:输出为空串,不正常。
[进一步尝试]
将格式化串中的中文去掉,改为英文,一切正常。
[查看源码]
查看CTime::Format的源码,发现其调用的基础函数:
_tcsftime(szBuffer, _countof(szBuffer), pFormat, ptmTemp)
看szBuffer和pFormat的类型:TCHAR,感觉应该支持Unicode。
[再次测试]
另写一个OCX,用Unicode版进行测试,输出是空串。
[仔细来分析原因]
我们来看看_tcsftime的Unicode版本,对它做个实验:
struct tm t = { 0, 0, 12, 25, 11, 93 };
wchar_t wsDest[255];
wchar_t wsFormat[] = L"最近计算时间: %Y,%m,%d %H:%M:%S";
size_t l = wcsftime(wsDest,255,wsFormat,&t);
wsDest[l] = L'/0';
::MessageBoxW(NULL,wsDest,L"test",MB_OK);
输出得到:空串。
将格式串换成英文:
wchar_t wsFormat[] = L"Last Time: %Y,%m,%d %H:%M:%S";
输出:Last Time: 1993,12,25 12:00:00
[结论]
CTime::Format 的 Unicode版居然不支持中文的格式化串。嘿。
[解决办法]
抛弃CTime这个低级垃圾东东,换上新式武器。
我另写了一个格式化的函数,为了与以前兼容,我仍接受CTime的输入。
CString CBaseUtil::FormatDateTime(const CTime &t)
{
CString sRet(_T(""));
if(!t.GetLocalTm()) return sRet; //t未初始化,不合法。
//或者断言 ASSERT(t.GetLocalTm())
//格式化串的格式可参见VarFormat的帮助
//如:最近计算时间: yyyy,mm,dd hh:nn:ss
CString sFormat = sFormat.LoadString(格式化串);
COleDateTime dt(t.GetYear(),t.GetMonth(),t.GetDay(),
t.GetHour(),t.GetMinute(),t.GetSecond());
COleVariant var(dt);
BSTR bstrOut = sRet.AllocSysString();
#ifdef _UNICODE
VarFormat(var,sFormat.GetBuffer(0),0,0,0,&bstrOut);
#else
USES_CONVERSION;
VarFormat(var,A2W(sFormat.GetBuffer(0)),0,0,0,&bstrOut);
#endif
sRet = bstrOut;
::SysFreeString(bstrOut);
return sRet;
}
好了,上述的做法就OK了,如果不用CTime做参数,那最好,因为CTime
范围也比较窄,可直接使用COleDateTime。
石头 于 2005-10-21
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tiger119/archive/2005/10/22/513526.aspx
==========================
补充
其实COleDateTime的Format也存在同样的问题,原因是
_LocaleUpdate _loc_update(plocinfo);
return _wcsftime_l_stat(
wstring,
maxsize,
wformat,
timeptr,
_loc_update.GetLocaleT());
//////
然后会导致
static size_t __cdecl _wcsftime_l_stat中
// if (_ERRCHECK_EINVAL_ERANGE(_wcstombs_s_l(NULL, format, flen * 2, wformat, flen * 2 - 1, plocinfo)) != 0)
// {
// goto done;
// }
这一句会错误。