better native date locale support

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59861 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Stefan Csomor
2009-03-26 10:17:19 +00:00
parent b6d74808f6
commit be8dbffa00

View File

@@ -1061,6 +1061,227 @@ static wxString GetLocaleDateFormat()
#endif // __WINDOWS__ #endif // __WINDOWS__
#ifdef __WXOSX__
#include "wx/osx/private.h"
// under OSX locale formats are defined using
// http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
//
// so we need a translation function, bluntly copied from the windows
// version above and enhanced with the additional elements needed
static wxString TranslateFromUnicodeFormat( const wxString& fmt)
{
wxString fmtWX;
wxChar chLast = _T('\0');
size_t lastCount = 0;
for ( const wxChar *p = fmt; /* NUL handled inside */; p++ )
{
if ( *p == chLast )
{
lastCount++;
continue;
}
switch ( *p )
{
// these characters come in groups, start counting them
case _T('d'):
case _T('M'):
case _T('y'):
case _T('g'):
case _T('h'):
case _T('H'):
case _T('m'):
case _T('s'):
chLast = *p;
lastCount = 1;
break;
default:
// first deal with any special characters we have had
if ( lastCount )
{
switch ( chLast )
{
case _T('d'):
switch ( lastCount )
{
case 1: // d
case 2: // dd
// these two are the same as we
// don't distinguish between 1 and
// 2 digits for days
fmtWX += _T("%d");
break;
case 3: // ddd
fmtWX += _T("%a");
break;
case 4: // dddd
fmtWX += _T("%A");
break;
default:
wxFAIL_MSG( _T("too many 'd's") );
}
break;
case _T('M'):
switch ( lastCount )
{
case 1: // M
case 2: // MM
// as for 'd' and 'dd' above
fmtWX += _T("%m");
break;
case 3:
fmtWX += _T("%b");
break;
case 4:
fmtWX += _T("%B");
break;
default:
wxFAIL_MSG( _T("too many 'M's") );
}
break;
case _T('y'):
switch ( lastCount )
{
case 1: // y
case 2: // yy
fmtWX += _T("%y");
break;
case 4: // yyyy
fmtWX += _T("%Y");
break;
default:
wxFAIL_MSG( _T("wrong number of 'y's") );
}
break;
case _T('H'):
switch ( lastCount )
{
case 1: // H
case 2: // HH
fmtWX += _T("%H");
break;
default:
wxFAIL_MSG( _T("wrong number of 'H's") );
}
break;
case _T('h'):
switch ( lastCount )
{
case 1: // h
case 2: // hh
fmtWX += _T("%h");
break;
default:
wxFAIL_MSG( _T("wrong number of 'h's") );
}
break;
case _T('m'):
switch ( lastCount )
{
case 1: // m
case 2: // mm
fmtWX += _T("%M");
break;
default:
wxFAIL_MSG( _T("wrong number of 'm's") );
}
break;
case _T('s'):
switch ( lastCount )
{
case 1: // s
case 2: // ss
fmtWX += _T("%S");
break;
default:
wxFAIL_MSG( _T("wrong number of 's's") );
}
break;
case _T('g'):
// strftime() doesn't have era string,
// ignore this format
wxASSERT_MSG( lastCount <= 2,
_T("too many 'g's") );
break;
default:
wxFAIL_MSG( _T("unreachable") );
}
chLast = _T('\0');
lastCount = 0;
}
// not a special character so must be just a separator,
// treat as is
if ( *p != _T('\0') )
{
if ( *p == _T('%') )
{
// this one needs to be escaped
fmtWX += _T('%');
}
fmtWX += *p;
}
}
if ( *p == _T('\0') )
break;
}
return fmtWX;
}
static wxString GetLocaleDateFormat()
{
wxCFRef<CFLocaleRef> currentLocale( CFLocaleCopyCurrent() );
wxCFRef<CFDateFormatterRef> dateFormatter( CFDateFormatterCreate
(NULL, currentLocale, kCFDateFormatterShortStyle, kCFDateFormatterNoStyle));
wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter ));
return TranslateFromUnicodeFormat(cfs.AsString());
}
static wxString GetLocaleFullDateFormat()
{
wxCFRef<CFLocaleRef> currentLocale( CFLocaleCopyCurrent() );
wxCFRef<CFDateFormatterRef> dateFormatter( CFDateFormatterCreate
(NULL, currentLocale, kCFDateFormatterLongStyle, kCFDateFormatterMediumStyle));
wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter ));
return TranslateFromUnicodeFormat(cfs.AsString());
}
#endif // __WXOSX__
bool bool
wxDateTime::ParseFormat(const wxString& date, wxDateTime::ParseFormat(const wxString& date,
const wxString& format, const wxString& format,
@@ -1222,21 +1443,43 @@ wxDateTime::ParseFormat(const wxString& date,
else // strptime() failed; try generic heuristic code else // strptime() failed; try generic heuristic code
#endif // HAVE_STRPTIME #endif // HAVE_STRPTIME
{ {
Tm tm;
#ifdef __WXOSX__
bool hasValidDate = false;
wxString fmtDate = GetLocaleFullDateFormat();
if ( !fmtDate.empty() )
{
const wxDateTime dt = ParseFormatAt
(
input,
end,
fmtDate
);
if ( dt.IsValid() )
{
tm = dt.GetTm();
hasValidDate = true;
}
}
// try the format which corresponds to ctime() output if ( !hasValidDate )
// first, then the generic date/time formats #endif // __WXOSX__
const wxDateTime dt = ParseFormatAt {
( // try the format which corresponds to ctime() output
input, // first, then the generic date/time formats
end, const wxDateTime dt = ParseFormatAt
wxS("%a %b %d %H:%M:%S %Y"), (
wxS("%x %X"), input,
wxS("%X %x") end,
); wxS("%a %b %d %H:%M:%S %Y"),
if ( !dt.IsValid() ) wxS("%x %X"),
return false; wxS("%X %x")
);
if ( !dt.IsValid() )
return false;
tm = dt.GetTm();
}
Tm tm = dt.GetTm();
hour = tm.hour; hour = tm.hour;
min = tm.min; min = tm.min;
@@ -1459,9 +1702,9 @@ wxDateTime::ParseFormat(const wxString& date,
wxString fmtDate, wxString fmtDate,
fmtDateAlt; fmtDateAlt;
#ifdef __WINDOWS__ #if defined( __WINDOWS__ ) || defined( __WXOSX__ )
// The above doesn't work for all locales, try to query // The above doesn't work for all locales, try to query
// Windows for the right way of formatting the date: // the OS for the right way of formatting the date:
fmtDate = GetLocaleDateFormat(); fmtDate = GetLocaleDateFormat();
if ( fmtDate.empty() ) if ( fmtDate.empty() )
#endif // __WINDOWS__ #endif // __WINDOWS__
@@ -1471,21 +1714,41 @@ wxDateTime::ParseFormat(const wxString& date,
{ {
fmtDate = _T("%d/%m/%y"); fmtDate = _T("%d/%m/%y");
fmtDateAlt = _T("%m/%d/%y"); fmtDateAlt = _T("%m/%d/%y");
} }
else // assume USA else // assume USA
{ {
fmtDate = _T("%m/%d/%y"); fmtDate = _T("%d/%m/%y");
fmtDateAlt = _T("%d/%m/%y"); fmtDateAlt = _T("%m/%d/%y");
} }
} }
const wxDateTime const wxDateTime
dt = ParseFormatAt(input, end, dt = ParseFormatAt(input, end,
fmtDate, fmtDateAlt); fmtDate, fmtDateAlt);
if ( !dt.IsValid() ) Tm tm;
return false;
Tm tm = dt.GetTm(); if ( !dt.IsValid() )
{
wxString fmtDateLong = fmtDate;
wxString fmtDateLongAlt = fmtDateAlt;
if ( !fmtDateLong.empty() )
{
fmtDateLong.Replace("%y","%Y");
fmtDateLongAlt.Replace("%y","%Y");
const wxDateTime dtLong = ParseFormatAt(input, end,
fmtDateLong, fmtDateLongAlt);
if ( !dtLong.IsValid() )
return false;
tm = dtLong.GetTm();
}
else
return false;
}
else
tm = dt.GetTm();
haveDay = haveDay =
haveMon = haveMon =