You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:28:14