Win32 API SHFormatDateTime函数前置异常特殊字符问题求助
解决SHFormatDateTime返回结果含特殊控制字符的问题
问题现象
遍历文件时,调用SHFormatDateTimeA或SHFormatDateTimeW处理WIN32_FIND_DATA中的ftLastWriteTime,无论传入FDTF_DEFAULT、FDTF_SHORTDATE等任何标志,返回的日期字符串都会带有奇怪的特殊字符:
- ANSI版本输出示例:
?4/?25/?2025 ??9:44 AM - Unicode版本输出示例:
u+200E 4 / u+200E 25 / u+200E 2025 u+200F u+200E 9 : 44 AM
原因分析
这些特殊字符是Unicode双向文本控制字符:
U+200E:左到右标记(LTR),用于强制文本按左到右顺序显示U+200F:右到左标记(RTL),用于强制文本按右到左顺序显示
当系统区域设置中包含双向语言(如阿拉伯语、希伯来语),或者日期格式模板里嵌入了这些控制字符时,SHFormatDateTime会严格遵循系统格式生成字符串,导致这些控制字符被包含在结果中。
解决方法
1. 过滤双向控制字符
直接从生成的字符串中移除U+200E、U+200F这类控制字符,适合需要保留SHFormatDateTime格式特性的场景。
Unicode版本代码示例:
#include <algorithm> #include <cwctype> // 判断是否为双向控制字符 bool isBidirectionalControl(wchar_t c) { return c == L'\u200E' || c == L'\u200F'; } // 处理逻辑 wchar_t datebuf[80]; DWORD flags = FDTF_DEFAULT; SHFormatDateTimeW(&findData.ftLastWriteTime, &flags, datebuf, 80); std::wstring lastModifiedDateStr(datebuf); // 过滤控制字符 lastModifiedDateStr.erase( std::remove_if(lastModifiedDateStr.begin(), lastModifiedDateStr.end(), isBidirectionalControl), lastModifiedDateStr.end() );
ANSI版本代码示例:
ANSI编码下,双向控制字符会被转成问号?,直接过滤即可(如果业务中需要保留正常问号,建议先转成Unicode处理后再转回ANSI):
#include <algorithm> // 处理逻辑 char datebuf[80]; DWORD flags = FDTF_DEFAULT; SHFormatDateTimeA(&findData.ftLastWriteTime, &flags, datebuf, 80); std::string lastModifiedDateStr(datebuf); // 过滤问号 lastModifiedDateStr.erase( std::remove(lastModifiedDateStr.begin(), lastModifiedDateStr.end(), '?'), lastModifiedDateStr.end() );
2. 改用GetDateFormat+GetTimeFormat替代
如果不需要Shell的特殊格式处理,用系统APIGetDateFormat和GetTimeFormat分别生成日期、时间字符串再组合,这两个函数默认不会包含双向控制字符,更适合通用场景。
Unicode版本代码示例:
wchar_t dateBuf[80]; wchar_t timeBuf[80]; // 获取短日期格式 GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &findData.ftLastWriteTime, nullptr, dateBuf, 80); // 获取时间格式 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &findData.ftLastWriteTime, nullptr, timeBuf, 80); // 组合日期和时间 std::wstring lastModifiedDateStr = std::wstring(dateBuf) + L" " + std::wstring(timeBuf);
ANSI版本代码示例:
char dateBuf[80]; char timeBuf[80]; GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &findData.ftLastWriteTime, nullptr, dateBuf, 80); GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &findData.ftLastWriteTime, nullptr, timeBuf, 80); std::string lastModifiedDateStr = std::string(dateBuf) + " " + std::string(timeBuf);
3. 修改系统区域格式(不推荐)
如果是个人测试环境,可以进入系统「区域设置」的日期格式编辑界面,手动移除模板中的双向控制字符,但此方法会影响系统全局设置,不适合应用程序层面的解决方案。
内容的提问来源于stack exchange,提问作者gene b.
相关产品推荐
相关产品推荐

