/** Sets the date and time using an ISO8601-formatted string * * @param str :: ISO8601 format string: "yyyy-mm-ddThh:mm:ss[Z+-]tz:tz" */ void DateAndTime::set_from_ISO8601_string(const std::string str) { //Make a copy std::string time = str; //Default of no timezone offset bool positive_offset = true; time_duration tz_offset = boost::posix_time::seconds(0); //Replace "T" with a space size_t n = time.find('T'); if (n != std::string::npos) { //Take out the T, for later time[n] = ' '; //Adjust for time zones. Fun! //Look for the time zone marker size_t n2; n2 = time.find('Z', n); if (n2 != std::string::npos) { //Found a Z. Remove it, and no timezone fix time = time.substr(0, n2); } else { //Look for a + or - indicating time zone offset size_t n_plus,n_minus,n5; n_plus = time.find('+', n); n_minus = time.find('-', n); if ((n_plus != std::string::npos) || (n_minus != std::string::npos)) { //Either a - or a + was found if (n_plus != std::string::npos) { positive_offset = true; n5 = n_plus; } else { positive_offset = false; n5 = n_minus; } //Now, parse the offset time std::string offset_str = time.substr(n5+1, time.size()-n5-1); //Take out the offset from time string time = time.substr(0, n5); //Separate into minutes and hours size_t n6; std::string hours_str("0"), minutes_str("0"); n6 = offset_str.find(':'); if ((n6 != std::string::npos)) { //Yes, minutes offset are specified minutes_str = offset_str.substr(n6+1, offset_str.size()-n6-1); hours_str = offset_str.substr(0, n6); } else //Just hours hours_str = offset_str; //Convert to a time_duration tz_offset = boost::posix_time::hours( boost::lexical_cast<long>(hours_str)) + boost::posix_time::minutes( boost::lexical_cast<long>(minutes_str)); } } } //The boost conversion will convert the string, then we subtract the time zone offset if (positive_offset) //The timezone is + so we need to subtract the hours this->set_from_ptime( boost::posix_time::time_from_string(time) - tz_offset ); else //The timezone is - so we need to ADD the hours this->set_from_ptime( boost::posix_time::time_from_string(time) + tz_offset ); }
/** Sets the date and time using an ISO8601-formatted string * * @param str :: ISO8601 format string: "yyyy-mm-ddThh:mm:ss[Z+-]tz:tz" * @param displayLogs :: flag to indiciate if the logs should be displayed */ void DateAndTime::setFromISO8601(const std::string &str, bool displayLogs) { // Make a copy std::string time = str; // Some ARGUS files have an invalid date with a space instead of zero. // To enable such files to be loaded we correct the date and issue a warning // (ticket #4017). std::string date = time.substr( 0, 10); // just take the date not the time or any date-time separator const size_t nSpace = date.find(' '); if (nSpace != std::string::npos) { if (displayLogs) { g_log.warning() << "Invalid ISO8601 date " << time; } time[nSpace] = '0'; // replace space with 0 // Do again in case of second space date[nSpace] = '0'; const size_t nSecondSpace = date.find(' '); if (nSecondSpace != std::string::npos) time[nSecondSpace] = '0'; if (displayLogs) { g_log.warning() << " corrected to " << time << '\n'; } } // Default of no timezone offset bool positive_offset = true; time_duration tz_offset = boost::posix_time::seconds(0); // Replace "T" with a space const size_t nCharT = time.find('T'); if (nCharT != std::string::npos) { // Take out the T, for later time[nCharT] = ' '; // Adjust for time zones. Fun! // Look for the time zone marker const size_t nCharZ = time.find('Z', nCharT); if (nCharZ != std::string::npos) { // Found a Z. Remove it, and no timezone fix time = time.substr(0, nCharZ); } else { // Look for a + or - indicating time zone offset size_t n_plus, n_minus; n_plus = time.find('+', nCharT); n_minus = time.find('-', nCharT); if ((n_plus != std::string::npos) || (n_minus != std::string::npos)) { size_t nPlusMinus; // Either a - or a + was found if (n_plus != std::string::npos) { positive_offset = true; nPlusMinus = n_plus; } else { positive_offset = false; nPlusMinus = n_minus; } // Now, parse the offset time std::string offset_str = time.substr(nPlusMinus + 1, time.size() - nPlusMinus - 1); // Take out the offset from time string time = time.substr(0, nPlusMinus); // Separate into minutes and hours std::string hours_str("0"), minutes_str("0"); const size_t nColon = offset_str.find(':'); if ((nColon != std::string::npos)) { // Yes, minutes offset are specified minutes_str = offset_str.substr(nColon + 1, offset_str.size() - nColon - 1); hours_str = offset_str.substr(0, nColon); } else // Just hours hours_str = offset_str; // Convert to a time_duration tz_offset = boost::posix_time::hours(boost::lexical_cast<long>(hours_str)) + boost::posix_time::minutes(boost::lexical_cast<long>(minutes_str)); } } } // The boost conversion will convert the string, then we subtract the time // zone offset // Different versions of boost accept slightly different things. Earlier // versions // seem to accept only a date as valid, whereas later versions do not. We want // the // string to always denote the full timestamp so we check for a colon and if // it is not present then throw an exception. if (time.find(':') == std::string::npos) throw std::invalid_argument("Error interpreting string '" + str + "' as a date/time."); try { if (positive_offset) // The timezone is + so we need to subtract the hours this->set_from_ptime(boost::posix_time::time_from_string(time) - tz_offset); else // The timezone is - so we need to ADD the hours this->set_from_ptime(boost::posix_time::time_from_string(time) + tz_offset); } catch (std::exception &) { // Re-throw a more helpful error message throw std::invalid_argument("Error interpreting string '" + str + "' as a date/time."); } }