winapi

Win32 API SHFormatDateTime function prepends unusual special characters


For some reason when I use the Win32 API SHFormatDateTime function to get a file's Modified Date, with any flag, it prepends some weird special characters, as follows.

This occurs in the context of looping through files (WIN32_FIND_DATAA findData), which may or may not be relevant here.

Simple ANSI version - SHFormatDateTimeA:

hFind = FindFirstFileA(full_path.c_str(), &findData);
while (FindNextFileA(hFind, &findData) != 0) {   

    char datebuf[80];
    DWORD flags = FDTF_DEFAULT;
    SHFormatDateTimeA(&findData.ftLastWriteTime, &flags, datebuf, 80);
    std::string lastModifiedDateStr = std::string(datebuf);

Output: ?4/?25/?2025 ??9:44 AM

Unicode version - SHFormatDateTimeW:

    wchar_t datebuf[80];
    DWORD flags = FDTF_DEFAULT;
    SHFormatDateTimeW(&findData.ftLastWriteTime, &flags, datebuf, 80);
    std::wstring lastModifiedDateStr = std::wstring(datebuf);

Output: u+200E‎ 4 / ‎u+200E 25 / ‎u+200E 2025 u+200F u+200E ‏‎9 : 44 AM

So regardless of ANSI/Unicode, the function SHFormatDateTime adds some weird chars before each part. I've tried various flags such as FDTF_DEFAULT, FDTF_SHORTDATE, and even NULL. I don't have this issue with other Shell WIn32 API functions.


Solution

  • U+200E‎ is LEFT-TO-RIGHT MARK. This ensures the formatted text is displayed in left-to-right order when processed in the context of a right-to-left language. If these marks are inserted, your flags variable will be updated to include the FDTF_RTLDATE or FDTF_LTRDATE flag accordingly (this is why the pdwflags parameter is [in, out]):

    FDTF_LTRDATE (0x00000100)

    Adds marks for left-to-right reading layout. This flag cannot be combined with FDTF_RTLDATE.

    FDTF_RTLDATE (0x00000200)

    Adds marks for right-to-left reading layout. This flag cannot be combined with FDTF_LTRDATE.

    For example:

    wchar_t datebuf[80];
    DWORD flags = FDTF_DEFAULT;
    SHFormatDateTimeW(&findData.ftLastWriteTime, &flags, datebuf, 80);
    
    if (flags & FDTF_LTRDATE) {
        // Left-To-Right marks have been inserted...
    }
    else if (flags & FDTF_RTLDATE) {
        // Right-To-Left marks have been inserted...
    }
    

    You can suppress this behavior by specifying the FDTF_NOAUTOREADINGORDER flag on input:

    FDTF_NOAUTOREADINGORDER (0x00000400)

    No reading order marks are inserted. Normally, in the absence of the FDTF_LTRDATE or FDTF_RTLDATE flag, SHFormatDateTime determines the reading order from the user's default locale, inserts reading order marks, and updates the pdwFlags output value appropriately. This flag prevents that process from occurring. It is used most commonly by legacy callers of SHFormatDateTime. This flag cannot be combined with FDTF_RTLDATE or FDTF_LTRDATE.

    DWORD flags = FDTF_DEFAULT | FDTF_NOAUTOREADINGORDER;