I'm looking for a low-level WinAPI to format date-time from FILETIME
to a localized string with an output of a date, time, or date and time together.
By reversing the MFC's COleDateTime
I was able to find VarBstrFromDate
function that "kinda" works. So I was trying to see if there's another more reliable API that can accomplish that.
There are two issues with VarBstrFromDate
that I could see:
1) It doesn't reliably report the date or time parts. For instance, if I call it as such for midnight Dec. 31, 1899
:
BSTR bstr = NULL;
HRESULT hr = ::VarBstrFromDate(1.0, LANG_USER_DEFAULT, VAR_FOURDIGITYEARS, &bstr);
::SysFreeString(bstr);
it returns "12/31/1899"
without the time part.
Or, if I call it for, say, noon Dec. 30, 1899
:
BSTR bstr = NULL;
HRESULT hr = ::VarBstrFromDate(0.5, LANG_USER_DEFAULT, VAR_FOURDIGITYEARS, &bstr);
::SysFreeString(bstr);
it returns "12:00:00 PM"
without the date part.
2) Additionally, conversion from FILETIME
to DATE
is somewhat tricky, especially for dates prior to Dec. 30, 1899. Again, by reversing MFC I was able to find that SystemTimeToVariantTime
can do it via the SYSTEMTIME
struct. Kinda backwards, but OK. But then I saw this monstrosity in the atlcore.h
:
inline BOOL AtlConvertSystemTimeToVariantTime(
_In_ const SYSTEMTIME& systimeSrc,
_Out_ double* pVarDtTm)
{
ATLENSURE(pVarDtTm!=NULL);
//Convert using ::SystemTimeToVariantTime and store the result in pVarDtTm then
//convert variant time back to system time and compare to original system time.
BOOL ok = ::SystemTimeToVariantTime(const_cast<SYSTEMTIME*>(&systimeSrc), pVarDtTm);
SYSTEMTIME sysTime;
::ZeroMemory(&sysTime, sizeof(SYSTEMTIME));
ok = ok && ::VariantTimeToSystemTime(*pVarDtTm, &sysTime);
ok = ok && (systimeSrc.wYear == sysTime.wYear &&
systimeSrc.wMonth == sysTime.wMonth &&
systimeSrc.wDay == sysTime.wDay &&
systimeSrc.wHour == sysTime.wHour &&
systimeSrc.wMinute == sysTime.wMinute &&
systimeSrc.wSecond == sysTime.wSecond);
return ok;
}
Do you know why they're checking the result returned by SystemTimeToVariantTime
by then passing it through VariantTimeToSystemTime
in such an awkward way? Does it mean that SystemTimeToVariantTime
may return an incorrect result, or what?
Anyway, I was thinking to find another API that wouldn't rely on conversion to a floating-point DATE
.
You can use the classic time functions in kernel32: First call FileTimeToSystemTime
and then call GetTimeFormat
and GetDateFormat
. SHFormatDateTime
is a wrapper around those functions.
The shell also has StrFromTimeInterval
if you need friendly text of time duration.