Parse also time zone in ParseDateTime(), if found

Accept the same kind of time zone specifiers that RFC822 timestamps
accept; most importantly the "+0200" style.

Added more tests, and changed the way tests compare dates:
Since some timestamps now specify a time zone, those need to be compared
as UTC to avoid the system's time zone affecting the tests. Others can
still be compared as local time, as before.
This commit is contained in:
Lauri Nurmi 2022-03-09 18:03:02 +02:00
parent 136b1713e1
commit fdd05c8b8b
2 changed files with 118 additions and 14 deletions

View File

@ -791,8 +791,13 @@ wxDateTime::ParseRFC822TimeZone(wxString::const_iterator *iterator,
}
else
{
// TZ is max 3 characters long; we do not want to consume
// characters beyond that.
wxString::const_iterator pPlusMax3 = pEnd;
if ( p != pEnd && p + 1 != pEnd && p + 2 != pEnd && p + 3 != pEnd )
pPlusMax3 = p + 3;
// abbreviation
const wxString tz(p, pEnd);
const wxString tz(p, pPlusMax3);
if ( tz == wxT("UT") || tz == wxT("UTC") || tz == wxT("GMT") )
offset = 0;
else if ( tz == wxT("AST") )
@ -1775,6 +1780,19 @@ wxDateTime::ParseDateTime(const wxString& date, wxString::const_iterator *end)
dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(),
dtTime.GetMillisecond());
// let's see if there is a time zone specified
// after date and/or time
if ( endBoth != date.end() && *endBoth == ' ' )
{
wxString::const_iterator tz = endBoth + 1;
if ( tz != date.end() &&
ParseRFC822TimeZone(&tz, date.end())
)
{
endBoth = tz;
}
}
*end = endBoth;
return true;

View File

@ -1416,23 +1416,26 @@ void DateTimeTestCase::TestDateTimeParse()
static const struct ParseTestData
{
const char *str;
Date date; // NB: this should be in UTC
Date date; // either local time or UTC
bool good;
const char *beyondEnd; // what remains unprocessed of the input
bool dateIsUTC; // true when timezone is specified
} parseTestDates[] =
{
{
"Thu 22 Nov 2007 07:40:00 PM",
{ 22, wxDateTime::Nov, 2007, 19, 40, 0 },
true,
""
"",
false
},
{
"2010-01-04 14:30",
{ 4, wxDateTime::Jan, 2010, 14, 30, 0 },
true,
""
"",
false
},
{
@ -1440,36 +1443,116 @@ void DateTimeTestCase::TestDateTimeParse()
"14:30:00 2020-01-04",
{ 4, wxDateTime::Jan, 2020, 14, 30, 0 },
true,
"",
false
},
{
"bloordyblop",
{ 1, wxDateTime::Jan, 9999, 0, 0, 0},
false,
"bloordyblop"
"bloordyblop",
false
},
{
"2022-03-09 19:12:05 and some text after space",
{ 9, wxDateTime::Mar, 2022, 19, 12, 5, -1 },
true,
" and some text after space"
" and some text after space",
false
},
{
// something other than a space right after time
"2022-03-09 19:12:05 ", // just a trailing space
{ 9, wxDateTime::Mar, 2022, 19, 12, 5, -1 },
true,
" ",
false
},
// something other than a space right after time
{
"2022-03-09 19:12:05AAaaaa",
{ 9, wxDateTime::Mar, 2022, 19, 12, 5, -1 },
true,
"AAaaaa"
"AAaaaa",
false
},
// the rest have a time zone specified, and when the
// time zone is valid, the date to compare to is in UTC
{
"2012-01-01 10:12:05 +0100",
{ 1, wxDateTime::Jan, 2012, 9, 12, 5, -1 },
true,
"",
true
},
{
"2012-01-01 10:12:05 +0100",
{ 1, wxDateTime::Jan, 2012, 10, 12, 5, -1 },
true, // ParseDateTime does know yet +0100, but
// ignoring that, parsing still succeeds
" +0100"
"2022-03-09 19:12:05 -0700",
{ 10, wxDateTime::Mar, 2022, 2, 12, 5, -1 },
true,
"",
true
},
{
"2022-03-09 19:12:05 +0615",
{ 9, wxDateTime::Mar, 2022, 12, 57, 5, -1 },
true,
"",
true
},
{
"2022-03-09 19:12:05 +0615 and some text",
{ 9, wxDateTime::Mar, 2022, 12, 57, 5, -1 },
true,
" and some text",
true
},
{
"2022-03-09 15:12:05 UTC",
{ 9, wxDateTime::Mar, 2022, 15, 12, 5, -1 },
true,
"",
true
},
{
"2022-03-09 15:12:05 UTC and some text",
{ 9, wxDateTime::Mar, 2022, 15, 12, 5, -1 },
true,
" and some text",
true
},
{
// date after time
"15:12:05 2022-03-09 UTC",
{ 9, wxDateTime::Mar, 2022, 15, 12, 5, -1 },
true,
"",
true
},
{
"2022-03-09 15:12:05 +010", // truncated time zone
{ 9, wxDateTime::Mar, 2022, 15, 12, 5, -1 },
true,
" +010",
false
},
{
"2022-03-09 15:12:05 GM", // truncated time zone
{ 9, wxDateTime::Mar, 2022, 15, 12, 5, -1 },
true,
" GM",
false
},
};
@ -1493,7 +1576,10 @@ void DateTimeTestCase::TestDateTimeParse()
parseTestDates[n].good
);
CPPUNIT_ASSERT_EQUAL( parseTestDates[n].date.DT(), dt );
wxDateTime dtReal = parseTestDates[n].dateIsUTC ?
parseTestDates[n].date.DT().FromUTC() :
parseTestDates[n].date.DT();
CPPUNIT_ASSERT_EQUAL( dtReal, dt );
CPPUNIT_ASSERT_EQUAL( wxString(parseTestDates[n].beyondEnd), wxString(end) );
}
else // failed to parse