fixed wxTimeSpan::Format() to behave more reasonably
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9509 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
e93bfe3c74
commit
df05cdc578
@ -15,6 +15,7 @@ wxBase:
|
||||
- wxCopyFile() respects the file permissions (Roland Scholz)
|
||||
- wxFTP::GetFileSize() added (Søren Erland Vestø)
|
||||
- wxDateTime::IsSameDate() bug fixed
|
||||
- wxTimeSpan::Format() now behaves more as expected, see docs
|
||||
|
||||
All (GUI):
|
||||
|
||||
|
@ -145,7 +145,7 @@ values as parameter:
|
||||
};
|
||||
\end{verbatim}
|
||||
|
||||
Differnet parst of the world use different conventions for the week start.
|
||||
Different parst of the world use different conventions for the week start.
|
||||
In some countries, the week starts on Sunday, while in others - on Monday.
|
||||
The ISO standard doesn't address this issue, so we support both conventions in
|
||||
the functions whose result depends on it (\helpref{GetWeekOfYear}{wxdatetimegetweekofyear} and
|
||||
@ -174,8 +174,8 @@ No base class
|
||||
\wxheading{See also}
|
||||
|
||||
\helpref{Date classes overview}{wxdatetimeoverview},\rtfsp
|
||||
wxTimeSpan,\rtfsp
|
||||
wxDateSpan,\rtfsp
|
||||
\helpref{wxTimeSpan}{wxtimespan},\rtfsp
|
||||
\helpref{wxDateSpan}{wxdatespan},\rtfsp
|
||||
\helpref{wxCalendarCtrl}{wxcalendarctrl}
|
||||
|
||||
\latexignore{\rtfignore{\wxheading{Function groups}}}
|
||||
|
@ -11,5 +11,76 @@
|
||||
|
||||
\section{\class{wxTimeSpan}}\label{wxtimespan}
|
||||
|
||||
TODO
|
||||
wxTimeSpan class represents a time interval.
|
||||
|
||||
\wxheading{Derived from}
|
||||
|
||||
No base class
|
||||
|
||||
\wxheading{Include files}
|
||||
|
||||
<wx/datetime.h>
|
||||
|
||||
\wxheading{See also}
|
||||
|
||||
\helpref{Date classes overview}{wxdatetimeoverview},\rtfsp
|
||||
\helpref{wxDateTime}{wxdatetime}
|
||||
|
||||
\latexignore{\rtfignore{\wxheading{Function groups}}}
|
||||
|
||||
\membersection{Static functions}
|
||||
|
||||
\membersection{Constructors}
|
||||
|
||||
\helpref{wxTimeSpan()}{wxtimespandef}
|
||||
\helpref{wxTimeSpan(hours, min, sec, msec)}{wxtimespan}
|
||||
|
||||
\membersection{Accessors}
|
||||
|
||||
\membersection{Operations}
|
||||
|
||||
\membersection{Tests}
|
||||
|
||||
\membersection{Formatting time spans}
|
||||
|
||||
\helpref{Format}{wxtimespanformat}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Start of member function part %
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\helponly{\insertatlevel{2}{
|
||||
\wxheading{Members}
|
||||
}}
|
||||
|
||||
\membersection{wxTimeSpan::Format}\label{wxtimespanformat}
|
||||
|
||||
\func{wxString}{Format}{\param{const wxChar * }{format = "\%H:\%M:\%S"}}
|
||||
|
||||
Returns the string containing the formatted representation of the time span.
|
||||
The following format specifiers are allowed after \%:
|
||||
|
||||
\twocolwidtha{5cm}%
|
||||
\begin{twocollist}\itemsep=0pt
|
||||
\twocolitem{H}{number of {\bf H}ours}
|
||||
\twocolitem{M}{number of {\bf M}inutes}
|
||||
\twocolitem{S}{number of {\bf S}econds}
|
||||
\twocolitem{l}{number of mi{\bf l}liseconds}
|
||||
\twocolitem{D}{number of {\bf D}ays}
|
||||
\twocolitem{E}{number of w{\bf E}eks}
|
||||
\twocolitem{\%}{the percent character}
|
||||
\end{twocollist}
|
||||
|
||||
Note that, for example, the number of hours in the description above is not
|
||||
well defined: it can be either the total number of hours (for example, for a
|
||||
time span of $50$ hours this would be $50$) or just the hour part of the time
|
||||
span, which would be $2$ in this case as $50$ hours is equal to $2$ days and
|
||||
$2$ hours.
|
||||
|
||||
wxTimeSpan resolves this ambiguity in the following way: if there had been,
|
||||
indeed, the {\tt \%D} format specified preceding the {\tt \%H}, then it is
|
||||
interpreted as $2$. Otherwise, it is $50$.
|
||||
|
||||
The same applies to all other format specifiers: if they follow a specifier of
|
||||
larger unit, only the rest part is taken, otherwise the full value is used.
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
//#define TEST_ARRAYS
|
||||
//#define TEST_CMDLINE
|
||||
//#define TEST_DATETIME
|
||||
#define TEST_DATETIME
|
||||
//#define TEST_DIR
|
||||
//#define TEST_DLLLOADER
|
||||
//#define TEST_ENVIRON
|
||||
@ -3383,6 +3383,32 @@ static void TestTimeZoneBug()
|
||||
puts("");
|
||||
}
|
||||
|
||||
static void TestTimeSpanFormat()
|
||||
{
|
||||
puts("\n*** wxTimeSpan tests ***");
|
||||
|
||||
static const char *formats[] =
|
||||
{
|
||||
_T("(default) %H:%M:%S"),
|
||||
_T("%E weeks and %D days"),
|
||||
_T("%l milliseconds"),
|
||||
_T("(with ms) %H:%M:%S:%l"),
|
||||
_T("100%% of minutes is %M"), // test "%%"
|
||||
_T("%D days and %H hours"),
|
||||
};
|
||||
|
||||
wxTimeSpan ts1(1, 2, 3, 4),
|
||||
ts2(111, 222, 333);
|
||||
for ( size_t n = 0; n < WXSIZEOF(formats); n++ )
|
||||
{
|
||||
printf("ts1 = %s\tts2 = %s\n",
|
||||
ts1.Format(formats[n]).c_str(),
|
||||
ts2.Format(formats[n]).c_str());
|
||||
}
|
||||
|
||||
puts("");
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
// test compatibility with the old wxDate/wxTime classes
|
||||
@ -4402,7 +4428,7 @@ int main(int argc, char **argv)
|
||||
#endif // TEST_TIMER
|
||||
|
||||
#ifdef TEST_DATETIME
|
||||
if ( 1 )
|
||||
if ( 0 )
|
||||
{
|
||||
TestTimeSet();
|
||||
TestTimeStatic();
|
||||
@ -4421,6 +4447,7 @@ int main(int argc, char **argv)
|
||||
|
||||
TestTimeZoneBug();
|
||||
}
|
||||
TestTimeSpanFormat();
|
||||
if ( 0 )
|
||||
TestDateTimeInteractive();
|
||||
#endif // TEST_DATETIME
|
||||
|
@ -152,10 +152,16 @@ IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule)
|
||||
// some trivial ones
|
||||
static const int MONTHS_IN_YEAR = 12;
|
||||
|
||||
static const int SECONDS_IN_MINUTE = 60;
|
||||
static const int SEC_PER_MIN = 60;
|
||||
|
||||
static const int MIN_PER_HOUR = 60;
|
||||
|
||||
static const int HOURS_PER_DAY = 24;
|
||||
|
||||
static const long SECONDS_PER_DAY = 86400l;
|
||||
|
||||
static const int DAYS_PER_WEEK = 7;
|
||||
|
||||
static const long MILLISECONDS_PER_DAY = 86400000l;
|
||||
|
||||
// this is the integral part of JDN of the midnight of Jan 1, 1970
|
||||
@ -3454,13 +3460,41 @@ wxString wxTimeSpan::Format(const wxChar *format) const
|
||||
wxString str;
|
||||
str.Alloc(wxStrlen(format));
|
||||
|
||||
// Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */)
|
||||
//
|
||||
// Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the
|
||||
// question is what should ts.Format("%S") do? The code here returns "3273"
|
||||
// in this case (i.e. the total number of seconds, not just seconds % 60)
|
||||
// because, for me, this call means "give me entire time interval in
|
||||
// seconds" and not "give me the seconds part of the time interval"
|
||||
//
|
||||
// If we agree that it should behave like this, it is clear that the
|
||||
// interpretation of each format specifier depends on the presence of the
|
||||
// other format specs in the string: if there was "%H" before "%M", we
|
||||
// should use GetMinutes() % 60, otherwise just GetMinutes() &c
|
||||
|
||||
// we remember the most important unit found so far
|
||||
enum TimeSpanPart
|
||||
{
|
||||
Part_Week,
|
||||
Part_Day,
|
||||
Part_Hour,
|
||||
Part_Min,
|
||||
Part_Sec,
|
||||
Part_MSec
|
||||
} partBiggest = Part_MSec;
|
||||
|
||||
for ( const wxChar *pch = format; *pch; pch++ )
|
||||
{
|
||||
wxChar ch = *pch;
|
||||
|
||||
if ( ch == _T('%') )
|
||||
{
|
||||
wxString tmp;
|
||||
// the start of the format specification of the printf() below
|
||||
wxString fmtPrefix = _T('%');
|
||||
|
||||
// the number
|
||||
long n;
|
||||
|
||||
ch = *++pch; // get the format spec char
|
||||
switch ( ch )
|
||||
@ -3470,44 +3504,90 @@ wxString wxTimeSpan::Format(const wxChar *format) const
|
||||
// fall through
|
||||
|
||||
case _T('%'):
|
||||
// will get to str << ch below
|
||||
break;
|
||||
str += ch;
|
||||
|
||||
// skip the part below switch
|
||||
continue;
|
||||
|
||||
case _T('D'):
|
||||
tmp.Printf(_T("%d"), GetDays());
|
||||
n = GetDays();
|
||||
if ( partBiggest < Part_Day )
|
||||
{
|
||||
n %= DAYS_PER_WEEK;
|
||||
}
|
||||
else
|
||||
{
|
||||
partBiggest = Part_Day;
|
||||
}
|
||||
break;
|
||||
|
||||
case _T('E'):
|
||||
tmp.Printf(_T("%d"), GetWeeks());
|
||||
partBiggest = Part_Week;
|
||||
n = GetWeeks();
|
||||
break;
|
||||
|
||||
case _T('H'):
|
||||
tmp.Printf(_T("%02d"), GetHours());
|
||||
n = GetHours();
|
||||
if ( partBiggest < Part_Hour )
|
||||
{
|
||||
n %= HOURS_PER_DAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
partBiggest = Part_Hour;
|
||||
}
|
||||
|
||||
fmtPrefix += _T("02");
|
||||
break;
|
||||
|
||||
case _T('l'):
|
||||
tmp.Printf(_T("%03ld"), GetMilliseconds().ToLong());
|
||||
n = GetMilliseconds().ToLong();
|
||||
if ( partBiggest < Part_MSec )
|
||||
{
|
||||
n %= 1000;
|
||||
}
|
||||
//else: no need to reset partBiggest to Part_MSec, it is
|
||||
// the least significant one anyhow
|
||||
|
||||
fmtPrefix += _T("03");
|
||||
break;
|
||||
|
||||
case _T('M'):
|
||||
tmp.Printf(_T("%02d"), GetMinutes());
|
||||
n = GetMinutes();
|
||||
if ( partBiggest < Part_Min )
|
||||
{
|
||||
n %= MIN_PER_HOUR;
|
||||
}
|
||||
else
|
||||
{
|
||||
partBiggest = Part_Min;
|
||||
}
|
||||
|
||||
fmtPrefix += _T("02");
|
||||
break;
|
||||
|
||||
case _T('S'):
|
||||
tmp.Printf(_T("%02ld"), GetSeconds().ToLong());
|
||||
n = GetSeconds().ToLong();
|
||||
if ( partBiggest < Part_Sec )
|
||||
{
|
||||
n %= SEC_PER_MIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
partBiggest = Part_Sec;
|
||||
}
|
||||
|
||||
fmtPrefix += _T("02");
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !!tmp )
|
||||
{
|
||||
str += tmp;
|
||||
|
||||
// skip str += ch below
|
||||
continue;
|
||||
}
|
||||
str += wxString::Format(fmtPrefix + _T("ld"), n);
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal character, just copy
|
||||
str += ch;
|
||||
}
|
||||
|
||||
str += ch;
|
||||
}
|
||||
|
||||
return str;
|
||||
|
Loading…
Reference in New Issue
Block a user