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:
@@ -15,6 +15,7 @@ wxBase:
|
|||||||
- wxCopyFile() respects the file permissions (Roland Scholz)
|
- wxCopyFile() respects the file permissions (Roland Scholz)
|
||||||
- wxFTP::GetFileSize() added (S<>ren Erland Vest<73>)
|
- wxFTP::GetFileSize() added (S<>ren Erland Vest<73>)
|
||||||
- wxDateTime::IsSameDate() bug fixed
|
- wxDateTime::IsSameDate() bug fixed
|
||||||
|
- wxTimeSpan::Format() now behaves more as expected, see docs
|
||||||
|
|
||||||
All (GUI):
|
All (GUI):
|
||||||
|
|
||||||
|
@@ -145,7 +145,7 @@ values as parameter:
|
|||||||
};
|
};
|
||||||
\end{verbatim}
|
\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.
|
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 ISO standard doesn't address this issue, so we support both conventions in
|
||||||
the functions whose result depends on it (\helpref{GetWeekOfYear}{wxdatetimegetweekofyear} and
|
the functions whose result depends on it (\helpref{GetWeekOfYear}{wxdatetimegetweekofyear} and
|
||||||
@@ -174,8 +174,8 @@ No base class
|
|||||||
\wxheading{See also}
|
\wxheading{See also}
|
||||||
|
|
||||||
\helpref{Date classes overview}{wxdatetimeoverview},\rtfsp
|
\helpref{Date classes overview}{wxdatetimeoverview},\rtfsp
|
||||||
wxTimeSpan,\rtfsp
|
\helpref{wxTimeSpan}{wxtimespan},\rtfsp
|
||||||
wxDateSpan,\rtfsp
|
\helpref{wxDateSpan}{wxdatespan},\rtfsp
|
||||||
\helpref{wxCalendarCtrl}{wxcalendarctrl}
|
\helpref{wxCalendarCtrl}{wxcalendarctrl}
|
||||||
|
|
||||||
\latexignore{\rtfignore{\wxheading{Function groups}}}
|
\latexignore{\rtfignore{\wxheading{Function groups}}}
|
||||||
|
@@ -11,5 +11,76 @@
|
|||||||
|
|
||||||
\section{\class{wxTimeSpan}}\label{wxtimespan}
|
\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_ARRAYS
|
||||||
//#define TEST_CMDLINE
|
//#define TEST_CMDLINE
|
||||||
//#define TEST_DATETIME
|
#define TEST_DATETIME
|
||||||
//#define TEST_DIR
|
//#define TEST_DIR
|
||||||
//#define TEST_DLLLOADER
|
//#define TEST_DLLLOADER
|
||||||
//#define TEST_ENVIRON
|
//#define TEST_ENVIRON
|
||||||
@@ -3383,6 +3383,32 @@ static void TestTimeZoneBug()
|
|||||||
puts("");
|
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
|
#if 0
|
||||||
|
|
||||||
// test compatibility with the old wxDate/wxTime classes
|
// test compatibility with the old wxDate/wxTime classes
|
||||||
@@ -4402,7 +4428,7 @@ int main(int argc, char **argv)
|
|||||||
#endif // TEST_TIMER
|
#endif // TEST_TIMER
|
||||||
|
|
||||||
#ifdef TEST_DATETIME
|
#ifdef TEST_DATETIME
|
||||||
if ( 1 )
|
if ( 0 )
|
||||||
{
|
{
|
||||||
TestTimeSet();
|
TestTimeSet();
|
||||||
TestTimeStatic();
|
TestTimeStatic();
|
||||||
@@ -4421,6 +4447,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
TestTimeZoneBug();
|
TestTimeZoneBug();
|
||||||
}
|
}
|
||||||
|
TestTimeSpanFormat();
|
||||||
if ( 0 )
|
if ( 0 )
|
||||||
TestDateTimeInteractive();
|
TestDateTimeInteractive();
|
||||||
#endif // TEST_DATETIME
|
#endif // TEST_DATETIME
|
||||||
|
@@ -152,10 +152,16 @@ IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule)
|
|||||||
// some trivial ones
|
// some trivial ones
|
||||||
static const int MONTHS_IN_YEAR = 12;
|
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 long SECONDS_PER_DAY = 86400l;
|
||||||
|
|
||||||
|
static const int DAYS_PER_WEEK = 7;
|
||||||
|
|
||||||
static const long MILLISECONDS_PER_DAY = 86400000l;
|
static const long MILLISECONDS_PER_DAY = 86400000l;
|
||||||
|
|
||||||
// this is the integral part of JDN of the midnight of Jan 1, 1970
|
// 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;
|
wxString str;
|
||||||
str.Alloc(wxStrlen(format));
|
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++ )
|
for ( const wxChar *pch = format; *pch; pch++ )
|
||||||
{
|
{
|
||||||
wxChar ch = *pch;
|
wxChar ch = *pch;
|
||||||
|
|
||||||
if ( ch == _T('%') )
|
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
|
ch = *++pch; // get the format spec char
|
||||||
switch ( ch )
|
switch ( ch )
|
||||||
@@ -3470,44 +3504,90 @@ wxString wxTimeSpan::Format(const wxChar *format) const
|
|||||||
// fall through
|
// fall through
|
||||||
|
|
||||||
case _T('%'):
|
case _T('%'):
|
||||||
// will get to str << ch below
|
str += ch;
|
||||||
break;
|
|
||||||
|
// skip the part below switch
|
||||||
|
continue;
|
||||||
|
|
||||||
case _T('D'):
|
case _T('D'):
|
||||||
tmp.Printf(_T("%d"), GetDays());
|
n = GetDays();
|
||||||
|
if ( partBiggest < Part_Day )
|
||||||
|
{
|
||||||
|
n %= DAYS_PER_WEEK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
partBiggest = Part_Day;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case _T('E'):
|
case _T('E'):
|
||||||
tmp.Printf(_T("%d"), GetWeeks());
|
partBiggest = Part_Week;
|
||||||
|
n = GetWeeks();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case _T('H'):
|
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;
|
break;
|
||||||
|
|
||||||
case _T('l'):
|
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;
|
break;
|
||||||
|
|
||||||
case _T('M'):
|
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;
|
break;
|
||||||
|
|
||||||
case _T('S'):
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !!tmp )
|
str += wxString::Format(fmtPrefix + _T("ld"), n);
|
||||||
{
|
}
|
||||||
str += tmp;
|
else
|
||||||
|
{
|
||||||
// skip str += ch below
|
// normal character, just copy
|
||||||
continue;
|
str += ch;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
str += ch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
|
Reference in New Issue
Block a user