Extract function tz_from_string.

Also changes from calculating the Bug 767824 offset to using
boost::date_time::local_time_in() and provides unit tests.
This commit is contained in:
John Ralls 2018-01-09 13:58:25 -08:00
parent e798df07d7
commit fcf88262ca
2 changed files with 58 additions and 45 deletions

View File

@ -262,48 +262,31 @@ GncDateTimeImpl::GncDateTimeImpl(const GncDateImpl& date, DayPart part) :
}
}
using PTZ = boost::local_time::posix_time_zone;
static TZ_Ptr
tz_from_string(std::string str)
{
if (str.empty()) return utc_zone;
std::string tzstr = "XXX" + str;
if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
tzstr.insert(6, ":");
if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
{
tzstr.insert(9, ":");
}
return TZ_Ptr(new PTZ(tzstr));
}
GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
m_time(unix_epoch, utc_zone)
{
if (str.empty()) return;
using std::string;
using PTZ = boost::local_time::posix_time_zone;
TZ_Ptr tzptr;
auto tzpos = str.find_first_of("+-", str.find(":"));
int offset = 0L;
if (tzpos != str.npos)
{
string tzstr = "XXX" + str.substr(tzpos);
if (tzstr.length() > 6 && tzstr[6] != ':') //6 for XXXsHH, s is + or -
tzstr.insert(6, ":");
if (tzstr.length() > 9 && tzstr[9] != ':') //9 for XXXsHH:MM
{
tzstr.insert(9, ":");
/* Bug 767824: A GLib bug in parsing the UTC timezone on
* Windows may have created a bogus timezone of a random
* number of minutes. Since there are no fractional-hour
* timezones around the prime meridian we can safely check for
* this in files by looking for minutes-only offsets and
* making the appropriate correction.
*/
if (tzstr.compare(7,8, "00") &&
(tzstr.length() > 10 ? tzstr[10] != '0' :
!tzstr.compare(10, 11, "00")))
{
offset = atoi(tzstr.substr(10,11).c_str());
if (offset && tzpos == '-')
offset = -offset;
tzstr.replace(10, 11, "00");
}
}
tzptr.reset(new PTZ(tzstr));
if (str[tzpos - 1] == ' ') --tzpos;
}
else
{
tzptr = utc_zone;
}
auto tzptr = tz_from_string(tzpos != str.npos ? str.substr(tzpos) : "");
if (tzpos != str.npos && str[tzpos - 1] == ' ') --tzpos;
try
{
using Facet = boost::posix_time::time_input_facet;
@ -328,8 +311,15 @@ GncDateTimeImpl::GncDateTimeImpl(const std::string str) :
{
throw(std::invalid_argument("The date string was outside of the supported year range."));
}
if (offset)
m_time -= boost::posix_time::minutes(offset);
/* Bug 767824: A GLib bug in parsing the UTC timezone on Windows may have
* created a bogus timezone of a random number of minutes. Since there are
* no fractional-hour timezones around the prime meridian we can safely
* check for this in files by resetting to UTC if there's a
* less-than-an-hour offset.
*/
auto offset = tzptr->base_utc_offset().seconds();
if (offset != 0 && std::abs(offset) < 3600)
m_time = m_time.local_time_in(utc_zone);
}
GncDateTimeImpl::operator time64() const
@ -460,7 +450,7 @@ GncDateTime::GncDateTime(const time64 time) :
m_impl(new GncDateTimeImpl(time)) {}
GncDateTime::GncDateTime(const struct tm tm) :
m_impl(new GncDateTimeImpl(tm)) {}
GncDateTime::GncDateTime(const std::string str) :
GncDateTime::GncDateTime(const std::string str, std::string fmt) :
m_impl(new GncDateTimeImpl(str)) {}
GncDateTime::~GncDateTime() = default;

View File

@ -261,15 +261,38 @@ TEST(gnc_datetime_constructors, test_time64_constructor)
TEST(gnc_datetime_constructors, test_string_constructor)
{
std::string timestr("2015-12-05 00:01:00");
GncDateTime time(timestr);
auto tm = time.utc_tm();
/* Plain UTC date-time */
std::string timestr("2015-12-05 11:57:03");
GncDateTime time1(timestr);
auto tm = time1.utc_tm();
EXPECT_EQ(tm.tm_year, 115);
EXPECT_EQ(tm.tm_mon, 11);
EXPECT_EQ(tm.tm_mday, 5);
EXPECT_EQ(tm.tm_hour, 0);
EXPECT_EQ(tm.tm_min, 1);
EXPECT_EQ(tm.tm_sec, 0);
EXPECT_EQ(tm.tm_hour,11);
EXPECT_EQ(tm.tm_min, 57);
EXPECT_EQ(tm.tm_sec, 3);
/* Datetime with an offset */
timestr = "1993-07-22 15:21:19 +0300";
GncDateTime time2(timestr);
tm = time2.utc_tm();
EXPECT_EQ(tm.tm_year, 93);
EXPECT_EQ(tm.tm_mon, 6);
EXPECT_EQ(tm.tm_mday, 22);
EXPECT_EQ(tm.tm_hour, 12);
EXPECT_EQ(tm.tm_min, 21);
EXPECT_EQ(tm.tm_sec, 19);
/* Bug 767824 date-time */
timestr = "1993-07-22 15:21:19 +0013";
GncDateTime time3(timestr);
tm = time3.utc_tm();
EXPECT_EQ(tm.tm_year, 93);
EXPECT_EQ(tm.tm_mon, 6);
EXPECT_EQ(tm.tm_mday, 22);
EXPECT_EQ(tm.tm_hour, 15);
EXPECT_EQ(tm.tm_min, 8);
EXPECT_EQ(tm.tm_sec, 19);
}
TEST(gnc_datetime_constructors, test_struct_tm_constructor)