LocalTime::LocalTime (string s)
{
- /* 2013-01-05T18:06:59 or 2013-01-05T18:06:59.123 or 2013-01-05T18:06:59+04:00 or 2013-01-05T18:06:59.123+04:00 */
- /* 0123456789012345678 or 01234567890123456789012 or 0123456789012345678901234 or 01234567890123456789012345678 */
+ /* 2013-01-05T18:06:59[.frac][TZ]
+ * Where .frac is fractional seconds
+ * TZ is something like +04:00
+ */
if (s.length() < 19) {
throw TimeFormatError (s);
}
- bool with_millisecond = false;
- bool with_tz = false;
-
- switch (s.length ()) {
- case 19:
- break;
- case 23:
- with_millisecond = true;
- break;
- case 25:
- with_tz = true;
- break;
- case 29:
- with_millisecond = with_tz = true;
- break;
- default:
- throw TimeFormatError (s);
- }
-
- int const tz_pos = with_millisecond ? 23 : 19;
+ /* Date and time with whole seconds */
- /* Check incidental characters */
if (s[4] != '-' || s[7] != '-' || s[10] != 'T' || s[13] != ':' || s[16] != ':') {
- throw TimeFormatError (s);
- }
- if (with_millisecond && s[19] != '.') {
- throw TimeFormatError (s);
- }
- if (with_tz && s[tz_pos] != '+' && s[tz_pos] != '-') {
- throw TimeFormatError (s);
+ throw TimeFormatError(s);
}
_year = lexical_cast<int>(s.substr(0, 4));
_hour = lexical_cast<int>(s.substr(11, 2));
_minute = lexical_cast<int>(s.substr(14, 2));
_second = lexical_cast<int>(s.substr(17, 2));
- _millisecond = with_millisecond ? lexical_cast<int>(s.substr(20, 3)) : 0;
- _offset.set_hour(with_tz ? lexical_cast<int>(s.substr(tz_pos + 1, 2)) : 0);
- _offset.set_minute(with_tz ? lexical_cast<int>(s.substr(tz_pos + 4, 2)) : 0);
+ size_t pos = 19;
+
+ /* Fractional seconds */
+ if (s.length() > pos && s[pos] == '.') {
+ auto end = s.find('+', pos);
+ if (end == std::string::npos) {
+ end = s.find('-', pos);
+ }
+ if (end == std::string::npos) {
+ end = s.length();
+ }
+ auto const length = end - pos;
+ _millisecond = lexical_cast<int>(s.substr(pos + 1, std::min(static_cast<size_t>(3), length - 1)));
+ pos = end;
+ } else {
+ _millisecond = 0;
+ }
- if (with_tz && s[tz_pos] == '-') {
- _offset.set_hour(-_offset.hour());
- _offset.set_minute(-_offset.minute());
+ /* Timezone */
+ if (pos != s.length()) {
+ if (s[pos] != '+' && s[pos] != '-') {
+ throw TimeFormatError(s);
+ }
+ if ((s.length() - pos) != 6) {
+ throw TimeFormatError(s);
+ }
+
+ _offset.set_hour(lexical_cast<int>(s.substr(pos + 1, 2)));
+ _offset.set_minute(lexical_cast<int>(s.substr(pos + 4, 2)));
+
+ if (s[pos] == '-') {
+ _offset.set_hour(-_offset.hour());
+ _offset.set_minute(-_offset.minute());
+ }
+ } else {
+ _offset.set_hour(0);
+ _offset.set_minute(0);
}
}
/* Correctly-formatted */
+ {
+ dcp::LocalTime t("2013-01-05T18:06:59");
+ BOOST_CHECK_EQUAL(t._year, 2013);
+ BOOST_CHECK_EQUAL(t._month, 1);
+ BOOST_CHECK_EQUAL(t._day, 5);
+ BOOST_CHECK_EQUAL(t._hour, 18);
+ BOOST_CHECK_EQUAL(t._minute, 6);
+ BOOST_CHECK_EQUAL(t._second, 59);
+ BOOST_CHECK(t._offset == dcp::UTCOffset(0, 0));
+ BOOST_CHECK_EQUAL(t.as_string(), "2013-01-05T18:06:59+00:00");
+ }
+
{
dcp::LocalTime t ("2013-01-05T18:06:59+04:00");
BOOST_CHECK_EQUAL (t._year, 2013);
BOOST_CHECK_EQUAL (t.as_string(false, false), "2011-11-20T01:06:59");
}
+ {
+ dcp::LocalTime t("2011-11-20T01:06:59.45678901-09:30");
+ BOOST_CHECK_EQUAL(t._year, 2011);
+ BOOST_CHECK_EQUAL(t._month, 11);
+ BOOST_CHECK_EQUAL(t._day, 20);
+ BOOST_CHECK_EQUAL(t._hour, 1);
+ BOOST_CHECK_EQUAL(t._minute, 6);
+ BOOST_CHECK_EQUAL(t._second, 59);
+ /* The fractional seconds here is truncated rather than rounded, for better or worse */
+ BOOST_CHECK_EQUAL(t._millisecond, 456);
+ BOOST_CHECK(t._offset == dcp::UTCOffset(-9, -30));
+ BOOST_CHECK_EQUAL(t.as_string(false, false), "2011-11-20T01:06:59");
+ }
+
{
/* Construction from boost::posix_time::ptime */
dcp::LocalTime b (boost::posix_time::time_from_string ("2002-01-20 19:03:56"));