@ -1331,25 +1331,106 @@ int nbDigitsFromNbLines(size_t nbLines)
return nbDigits ;
}
namespace
{
constexpr TCHAR timeFmtEscapeChar = 0x1 ;
constexpr TCHAR middayFormat [ ] = _T ( " tt " ) ;
// Returns AM/PM string defined by the system locale for the specified time.
// This string may be empty or customized.
generic_string getMiddayString ( const TCHAR * localeName , const SYSTEMTIME & st )
{
generic_string midday ;
midday . resize ( MAX_PATH ) ;
int ret = GetTimeFormatEx ( localeName , 0 , & st , middayFormat , & midday [ 0 ] , static_cast < int > ( midday . size ( ) ) ) ;
if ( ret > 0 )
midday . resize ( ret - 1 ) ; // Remove the null-terminator.
else
midday . clear ( ) ;
return midday ;
}
// Replaces conflicting time format specifiers by a special character.
bool escapeTimeFormat ( generic_string & format )
{
bool modified = false ;
for ( auto & ch : format )
{
if ( ch = = middayFormat [ 0 ] )
{
ch = timeFmtEscapeChar ;
modified = true ;
}
}
return modified ;
}
// Replaces special time format characters by actual AM/PM string.
void unescapeTimeFormat ( generic_string & format , const generic_string & midday )
{
if ( midday . empty ( ) )
{
auto it = std : : remove ( format . begin ( ) , format . end ( ) , timeFmtEscapeChar ) ;
if ( it ! = format . end ( ) )
format . erase ( it , format . end ( ) ) ;
}
else
{
size_t i = 0 ;
while ( ( i = format . find ( timeFmtEscapeChar , i ) ) ! = generic_string : : npos )
{
if ( i + 1 < format . size ( ) & & format [ i + 1 ] = = timeFmtEscapeChar )
{
// 'tt' => AM/PM
format . erase ( i , std : : size ( middayFormat ) - 1 ) ;
format . insert ( i , midday ) ;
}
else
{
// 't' => A/P
format [ i ] = midday [ 0 ] ;
}
}
}
}
}
generic_string getDateTimeStrFrom ( const generic_string & dateTimeFormat , const SYSTEMTIME & st )
{
generic_string dateTimeStr = dateTimeFormat ;
dateTimeStr = stringReplace ( dateTimeStr , TEXT ( " Y " ) , std : : to_wstring ( st . wYear ) ) ;
wchar_t buf [ 3 ] ;
_snwprintf ( buf , sizeof ( buf ) , TEXT ( " %02d " ) , st . wMonth ) ;
dateTimeStr = stringReplace ( dateTimeStr , TEXT ( " M " ) , buf ) ;
const TCHAR * localeName = LOCALE_NAME_USER_DEFAULT ;
const DWORD flags = 0 ;
constexpr int bufferSize = MAX_PATH ;
TCHAR buffer [ bufferSize ] = { } ;
int ret = 0 ;
_snwprintf ( buf , sizeof ( buf ) , TEXT ( " %02d " ) , st . wDay ) ;
dateTimeStr = stringReplace ( dateTimeStr , TEXT ( " D " ) , buf ) ;
_snwprintf ( buf , sizeof ( buf ) , TEXT ( " %02d " ) , st . wHour ) ;
dateTimeStr = stringReplace ( dateTimeStr , TEXT ( " h " ) , buf ) ;
// 1. Escape 'tt' that means AM/PM or 't' that means A/P.
// This is needed to avoid conflict with 'M' date format that stands for month.
generic_string newFormat = dateTimeFormat ;
const bool hasMiddayFormat = escapeTimeFormat ( newFormat ) ;
_snwprintf ( buf , sizeof ( buf ) , TEXT ( " %02d " ) , st . wMinute ) ;
dateTimeStr = stringReplace ( dateTimeStr , TEXT ( " m " ) , buf ) ;
// 2. Format the time (h/m/s/t/H).
ret = GetTimeFormatEx ( localeName , flags , & st , newFormat . c_str ( ) , buffer , bufferSize ) ;
if ( ret ! = 0 )
{
// 3. Format the date (d/y/g/M).
// Now use the buffer as a format string to process the format specifiers not recognized by GetTimeFormatEx().
ret = GetDateFormatEx ( localeName , flags , & st , buffer , buffer , bufferSize , nullptr ) ;
}
_snwprintf ( buf , sizeof ( buf ) , TEXT ( " %02d " ) , st . wSecond ) ;
dateTimeStr = stringReplace ( dateTimeStr , TEXT ( " s " ) , buf ) ;
if ( ret ! = 0 )
{
if ( hasMiddayFormat )
{
// 4. Now format only the AM/PM string.
const generic_string midday = getMiddayString ( localeName , st ) ;
generic_string result = buffer ;
unescapeTimeFormat ( result , midday ) ;
return result ;
}
return buffer ;
}
return dateTimeStr ;
return { } ;
}