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:
Vadim Zeitlin 2001-03-13 13:17:46 +00:00
parent e93bfe3c74
commit df05cdc578
5 changed files with 204 additions and 25 deletions

View File

@ -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):

View File

@ -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}}}

View File

@ -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.

View File

@ -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

View File

@ -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;