Add support for "%V" and "%G" to wxDateTime::Format().
This is useful for creating ISO 8601 week number based stamps. Closes #11857. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76988 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
db65392b95
commit
29b68052bb
@ -799,6 +799,10 @@ public:
|
||||
function (http://www.cplusplus.com/reference/clibrary/ctime/strftime.html).
|
||||
Please see its description for the meaning of @a format parameter.
|
||||
|
||||
Notice that POSIX @c "%g", @c "%G", @c "%V" and @c "%z" format
|
||||
specifiers are supported even if the standard library doesn't support
|
||||
them (e.g. MSVC).
|
||||
|
||||
It also accepts a few wxWidgets-specific extensions: you can optionally
|
||||
specify the width of the field to follow using @c printf(3)-like syntax
|
||||
and the format specification @c "%l" can be used to get the number of
|
||||
|
@ -271,6 +271,30 @@ GetWeekDayFromName(wxString::const_iterator& p,
|
||||
return wd;
|
||||
}
|
||||
|
||||
// return the year of the Monday of the week containing the given date
|
||||
int
|
||||
GetWeekBasedYear(const wxDateTime& dt)
|
||||
{
|
||||
const wxDateTime::Tm tm = dt.GetTm();
|
||||
|
||||
int year = tm.year;
|
||||
|
||||
// The week-based year can only be different from the normal year for few
|
||||
// days in the beginning and the end of the year.
|
||||
if ( tm.yday > 361 )
|
||||
{
|
||||
if ( dt.GetWeekOfYear() == 1 )
|
||||
year++;
|
||||
}
|
||||
else if ( tm.yday < 5 )
|
||||
{
|
||||
if ( dt.GetWeekOfYear() == 53 )
|
||||
year--;
|
||||
}
|
||||
|
||||
return year;
|
||||
}
|
||||
|
||||
// parses string starting at given iterator using the specified format and,
|
||||
// optionally, a fall back format (and optionally another one... but it stops
|
||||
// there, really)
|
||||
@ -321,17 +345,38 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const
|
||||
format.Replace("%X",wxLocale::GetInfo(wxLOCALE_TIME_FMT));
|
||||
#endif
|
||||
// we have to use our own implementation if the date is out of range of
|
||||
// strftime() or if we use non standard specifiers (notice that "%z" is
|
||||
// special because it is de facto standard under Unix but is not supported
|
||||
// under Windows)
|
||||
// strftime()
|
||||
#ifdef wxHAS_STRFTIME
|
||||
time_t time = GetTicks();
|
||||
|
||||
if ( (time != (time_t)-1) && !wxStrstr(format, wxT("%l"))
|
||||
bool canUseStrftime = time != (time_t)-1;
|
||||
|
||||
// We also can't use strftime() if we use non standard specifier: either
|
||||
// our own extension "%l" or one of "%g", "%G", "%V", "%z" which are POSIX
|
||||
// but not supported under Windows.
|
||||
for ( wxString::const_iterator p = format.begin();
|
||||
canUseStrftime && p != format.end();
|
||||
++p )
|
||||
{
|
||||
if ( *p != '%' )
|
||||
continue;
|
||||
|
||||
// set the default format
|
||||
switch ( (*++p).GetValue() )
|
||||
{
|
||||
case 'l':
|
||||
#ifdef __WINDOWS__
|
||||
&& !wxStrstr(format, wxT("%z"))
|
||||
#endif
|
||||
)
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'V':
|
||||
case 'z':
|
||||
#endif // __WINDOWS__
|
||||
canUseStrftime = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( canUseStrftime )
|
||||
{
|
||||
// use strftime()
|
||||
struct tm tmstruct;
|
||||
@ -405,6 +450,7 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const
|
||||
switch ( (*++p).GetValue() )
|
||||
{
|
||||
case wxT('Y'): // year has 4 digits
|
||||
case wxT('G'): // (and ISO week year too)
|
||||
case wxT('z'): // time zone as well
|
||||
fmt = wxT("%04d");
|
||||
break;
|
||||
@ -576,6 +622,14 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const
|
||||
res += wxString::Format(fmt, tm.mday);
|
||||
break;
|
||||
|
||||
case wxT('g'): // 2-digit week-based year
|
||||
res += wxString::Format(fmt, GetWeekBasedYear(*this) % 100);
|
||||
break;
|
||||
|
||||
case wxT('G'): // week-based year with century
|
||||
res += wxString::Format(fmt, GetWeekBasedYear(*this));
|
||||
break;
|
||||
|
||||
case wxT('H'): // hour in 24h format (00-23)
|
||||
res += wxString::Format(fmt, tm.hour);
|
||||
break;
|
||||
@ -621,6 +675,7 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const
|
||||
res += wxString::Format(fmt, GetWeekOfYear(Sunday_First, tz));
|
||||
break;
|
||||
|
||||
case wxT('V'): // ISO week number
|
||||
case wxT('W'): // week number in the year (Monday 1st week day)
|
||||
res += wxString::Format(fmt, GetWeekOfYear(Monday_First, tz));
|
||||
break;
|
||||
|
@ -228,6 +228,7 @@ private:
|
||||
CPPUNIT_TEST( TestDateParse );
|
||||
CPPUNIT_TEST( TestDateParseISO );
|
||||
CPPUNIT_TEST( TestDateTimeParse );
|
||||
CPPUNIT_TEST( TestDateWeekFormat );
|
||||
CPPUNIT_TEST( TestTimeArithmetics );
|
||||
CPPUNIT_TEST( TestDSTBug );
|
||||
CPPUNIT_TEST( TestDateOnly );
|
||||
@ -247,6 +248,7 @@ private:
|
||||
void TestDateParse();
|
||||
void TestDateParseISO();
|
||||
void TestDateTimeParse();
|
||||
void TestDateWeekFormat();
|
||||
void TestTimeArithmetics();
|
||||
void TestDSTBug();
|
||||
void TestDateOnly();
|
||||
@ -1212,6 +1214,85 @@ void DateTimeTestCase::TestDateTimeParse()
|
||||
}
|
||||
}
|
||||
|
||||
void DateTimeTestCase::TestDateWeekFormat()
|
||||
{
|
||||
static const struct DateWeekTestData
|
||||
{
|
||||
int y, m, d;
|
||||
const char* result; // expected output of "%G%V"
|
||||
} testWeeks[] =
|
||||
{
|
||||
// Some manual test cases.
|
||||
{ 2014, 1, 1, "2014-01" },
|
||||
{ 2014, 1, 2, "2014-01" },
|
||||
{ 2014, 1, 3, "2014-01" },
|
||||
{ 2014, 1, 4, "2014-01" },
|
||||
{ 2014, 1, 5, "2014-01" },
|
||||
{ 2014, 1, 6, "2014-02" },
|
||||
{ 2014, 1, 7, "2014-02" },
|
||||
{ 2014, 12, 24, "2014-52" },
|
||||
{ 2014, 12, 25, "2014-52" },
|
||||
{ 2014, 12, 26, "2014-52" },
|
||||
{ 2014, 12, 27, "2014-52" },
|
||||
{ 2014, 12, 28, "2014-52" },
|
||||
{ 2014, 12, 29, "2015-01" },
|
||||
{ 2014, 12, 30, "2015-01" },
|
||||
{ 2014, 12, 31, "2015-01" },
|
||||
{ 2015, 12, 24, "2015-52" },
|
||||
{ 2015, 12, 25, "2015-52" },
|
||||
{ 2015, 12, 26, "2015-52" },
|
||||
{ 2015, 12, 27, "2015-52" },
|
||||
{ 2015, 12, 28, "2015-53" },
|
||||
{ 2015, 12, 29, "2015-53" },
|
||||
{ 2015, 12, 30, "2015-53" },
|
||||
{ 2015, 12, 31, "2015-53" },
|
||||
{ 2016, 1, 1, "2015-53" },
|
||||
{ 2016, 1, 2, "2015-53" },
|
||||
{ 2016, 1, 3, "2015-53" },
|
||||
{ 2016, 1, 4, "2016-01" },
|
||||
{ 2016, 1, 5, "2016-01" },
|
||||
{ 2016, 1, 6, "2016-01" },
|
||||
{ 2016, 1, 7, "2016-01" },
|
||||
|
||||
// The rest of the tests was generated using the following zsh command:
|
||||
//
|
||||
// for n in {0..19}; date --date $((RANDOM%100 + 2000))-$((RANDOM%12+1))-$((RANDOM%31+1)) +'{ %Y, %_m, %_d, "%G-%V" },'
|
||||
//
|
||||
// (ignore invalid dates if any are randomly created).
|
||||
{ 2017, 11, 28, "2017-48" },
|
||||
{ 2086, 9, 6, "2086-36" },
|
||||
{ 2060, 11, 11, "2060-46" },
|
||||
{ 2009, 5, 10, "2009-19" },
|
||||
{ 2032, 12, 8, "2032-50" },
|
||||
{ 2025, 4, 7, "2025-15" },
|
||||
{ 2080, 5, 20, "2080-21" },
|
||||
{ 2077, 7, 19, "2077-29" },
|
||||
{ 2084, 12, 17, "2084-50" },
|
||||
{ 2071, 4, 13, "2071-16" },
|
||||
{ 2006, 1, 3, "2006-01" },
|
||||
{ 2053, 8, 1, "2053-31" },
|
||||
{ 2097, 8, 14, "2097-33" },
|
||||
{ 2067, 1, 3, "2067-01" },
|
||||
{ 2039, 9, 27, "2039-39" },
|
||||
{ 2095, 2, 10, "2095-06" },
|
||||
{ 2004, 7, 7, "2004-28" },
|
||||
{ 2049, 12, 27, "2049-52" },
|
||||
{ 2071, 8, 19, "2071-34" },
|
||||
{ 2010, 11, 30, "2010-48" },
|
||||
};
|
||||
|
||||
for ( size_t n = 0; n < WXSIZEOF(testWeeks); n++ )
|
||||
{
|
||||
const DateWeekTestData& td = testWeeks[n];
|
||||
wxDateTime d(td.d, wxDateTime::Month(td.m - 1), td.y);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL( td.result, d.Format("%G-%V") );
|
||||
|
||||
if ( td.y > 2000 )
|
||||
CPPUNIT_ASSERT_EQUAL( td.result + 2, d.Format("%g-%V") );
|
||||
}
|
||||
}
|
||||
|
||||
void DateTimeTestCase::TestTimeArithmetics()
|
||||
{
|
||||
static const wxDateSpan testArithmData[] =
|
||||
|
Loading…
Reference in New Issue
Block a user