From fdd05c8b8b3ad737302a0f74da5971e1958b940e Mon Sep 17 00:00:00 2001 From: Lauri Nurmi Date: Wed, 9 Mar 2022 18:03:02 +0200 Subject: [PATCH] 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. --- src/common/datetimefmt.cpp | 20 +++++- tests/datetime/datetimetest.cpp | 112 ++++++++++++++++++++++++++++---- 2 files changed, 118 insertions(+), 14 deletions(-) diff --git a/src/common/datetimefmt.cpp b/src/common/datetimefmt.cpp index 4642816fea..5a0e41a0b7 100644 --- a/src/common/datetimefmt.cpp +++ b/src/common/datetimefmt.cpp @@ -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; diff --git a/tests/datetime/datetimetest.cpp b/tests/datetime/datetimetest.cpp index 9a48b3a781..654fe325d5 100644 --- a/tests/datetime/datetimetest.cpp +++ b/tests/datetime/datetimetest.cpp @@ -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