Newer
Older
#include <Poco/DateTime.h>
#include <Poco/DateTimeFormat.h>
#include <Poco/DateTimeParser.h>
namespace Mantid {
namespace Kernel {
Logger g_log("DateAndTime");
Janik Zikovsky
committed
/// Max allowed nanoseconds in the time; 2^62-1
const int64_t MAX_NANOSECONDS = 4611686018427387903LL;
Janik Zikovsky
committed
/// Max allowed seconds in the time
const int64_t MAX_SECONDS = 4611686017LL;
Janik Zikovsky
committed
/// Min allowed nanoseconds in the time; -2^62+1
const int64_t MIN_NANOSECONDS = -4611686018427387903LL;
Janik Zikovsky
committed
/// Min allowed seconds in the time
const int64_t MIN_SECONDS = -4611686017LL;
/// Number of nanoseconds in one second
const int64_t NANO_PER_SEC = 1000000000LL;
Janik Zikovsky
committed
Janik Zikovsky
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Convert time_t to tm as UTC time.
* Portable implementation of gmtime_r (re-entrant gmtime) that works on Windows
*and Linux
Janik Zikovsky
committed
*
Janik Zikovsky
committed
* @param clock :: pointer to time_t to convert
* @param result :: pointer to a struct tm (timeinfo structure) that will be
*filled.
* @return result if successful, or NULL if there was an error.
Janik Zikovsky
committed
*/
std::tm *gmtime_r_portable(const std::time_t *clock, struct std::tm *result) {
Janik Zikovsky
committed
#ifdef _WIN32
// Windows implementation
if (!gmtime_s(result, clock)) { // Returns zero if successful
Janik Zikovsky
committed
return result;
} else { // Returned some non-zero error code
Janik Zikovsky
committed
return NULL;
}
#else
Janik Zikovsky
committed
return gmtime_r(clock, result);
#endif
}
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/// utc_mktime() converts a struct tm that contains
/// broken down time in utc to a time_t. This function uses
/// a brute-force method of conversion that does not require
/// the environment variable TZ to be changed at all, and is
/// therefore slightly more thread-safe in that regard.
///
/// The difference between mktime() and utc_mktime() is that
/// standard mktime() expects the struct tm to be in localtime,
/// according to the current TZ and system setting, while utc_mktime()
/// always assumes that the struct tm is in UTC, and converts it
/// to time_t regardless of what TZ is currently set.
///
/// The difference between utc_mktime() and TzWrapper::iso_mktime()
/// is that iso_mktime() will parse straight from an ISO string,
/// and if the ISO timestamp ends in a 'Z', it will behave like
/// utc_mktime() except it will alter the TZ environment variable
/// to do it. If the ISO timestamp has no 'Z', then iso_mktime()
/// behaves like mktime().
///
/// Copyright (C) 2010, Chris Frey <cdfrey@foursquare.net>, To God be the
/// glory
Janik Zikovsky
committed
/// Released to the public domain.
time_t utc_mktime(struct tm *utctime) {
Janik Zikovsky
committed
time_t result;
struct tm tmp, check;
// loop, converting "local time" to time_t and back to utc tm,
// and adjusting until there are no differences... this
// automatically takes care of DST issues.
// do first conversion
tmp = *utctime;
tmp.tm_isdst = -1;
result = mktime(&tmp);
Janik Zikovsky
committed
return (time_t)-1;
if (gmtime_r_portable(&result, &check) == NULL)
Janik Zikovsky
committed
return (time_t)-1;
// loop until match
Janik Zikovsky
committed
int counter = 0;
while (counter < 15 && (check.tm_year != utctime->tm_year ||
check.tm_mon != utctime->tm_mon ||
check.tm_mday != utctime->tm_mday ||
check.tm_hour != utctime->tm_hour ||
check.tm_min != utctime->tm_min)) {
tmp.tm_min += utctime->tm_min - check.tm_min;
Janik Zikovsky
committed
tmp.tm_hour += utctime->tm_hour - check.tm_hour;
tmp.tm_mday += utctime->tm_mday - check.tm_mday;
tmp.tm_mon += utctime->tm_mon - check.tm_mon;
Janik Zikovsky
committed
tmp.tm_year += utctime->tm_year - check.tm_year;
tmp.tm_isdst = -1;
result = mktime(&tmp);
Janik Zikovsky
committed
return (time_t)-1;
Janik Zikovsky
committed
gmtime_r_portable(&result, &check);
if (gmtime_r_portable(&result, &check) == NULL)
Janik Zikovsky
committed
return (time_t)-1;
// Seems like there can be endless loops at the end of a month? E.g. sep 30,
// 2010 at 4:40 pm. This is to avoid it.
Janik Zikovsky
committed
counter++;
Janik Zikovsky
committed
}
return result;
}
} // namespace DateAndTimeHelpers
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Default, empty constructor */
DateAndTime::DateAndTime() : _nanoseconds(0) {}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Construct a date from nanoseconds.
Janik Zikovsky
committed
* @param total_nanoseconds :: nanoseconds since Jan 1, 1990 (our epoch).
Janik Zikovsky
committed
*/
DateAndTime::DateAndTime(const int64_t total_nanoseconds) {
// Make sure that you cannot construct a date that is beyond the limits...
Janik Zikovsky
committed
if (total_nanoseconds > MAX_NANOSECONDS)
_nanoseconds = MAX_NANOSECONDS;
else if (total_nanoseconds < MIN_NANOSECONDS)
_nanoseconds = MIN_NANOSECONDS;
else
_nanoseconds = total_nanoseconds;
Gigg, Martyn Anthony
committed
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Construct a time from an ISO8601 string
*
* @param ISO8601_string: and ISO8601 formatted string.
* "yyyy-mm-ddThh:mm:ss[Z+-]tz:tz"; although the T can be replaced by a
*space.
* The time must included, but the time-zone specification is optional.
*@param displayLogs :: if the logs should be dsiplayed during the execution of
*the constructor
Janik Zikovsky
committed
*/
DateAndTime::DateAndTime(const std::string ISO8601_string, bool displayLogs)
: _nanoseconds(0) {
this->setFromISO8601(ISO8601_string, displayLogs);
Janik Zikovsky
committed
}
//------------------------------------------------------------------------------------------------
/** Construct time from a boost::posix_time::ptime.
Janik Zikovsky
committed
* @param _ptime :: boost::posix_time::ptime
Janik Zikovsky
committed
*/
DateAndTime::DateAndTime(const boost::posix_time::ptime _ptime)
: _nanoseconds(0) {
Janik Zikovsky
committed
this->set_from_ptime(_ptime);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Construct a time from the number of seconds and nanoseconds since Jan 1,
* 1990.
Janik Zikovsky
committed
* @param seconds :: seconds since Jan 1, 1990.
* @param nanoseconds :: nanoseconds to add to the number of seconds
Janik Zikovsky
committed
*/
DateAndTime::DateAndTime(const double seconds, const double nanoseconds) {
Janik Zikovsky
committed
double nano = seconds * 1e9 + nanoseconds;
Janik Zikovsky
committed
if (nano > MAX_NANOSECONDS)
_nanoseconds = MAX_NANOSECONDS;
else if (nano < MIN_NANOSECONDS)
_nanoseconds = MIN_NANOSECONDS;
else
_nanoseconds = static_cast<int64_t>(nano);
Janik Zikovsky
committed
}
Gigg, Martyn Anthony
committed
//------------------------------------------------------------------------------------------------
/** Construct a time from the number of seconds and nanoseconds since Jan 1,
* 1990.
Janik Zikovsky
committed
* @param seconds :: seconds since Jan 1, 1990.
* @param nanoseconds :: nanoseconds to add to the number of seconds
Janik Zikovsky
committed
*/
DateAndTime::DateAndTime(const int64_t seconds, const int64_t nanoseconds) {
Janik Zikovsky
committed
if (seconds >= MAX_SECONDS)
_nanoseconds = MAX_NANOSECONDS;
else if (seconds <= MIN_SECONDS)
_nanoseconds = MIN_NANOSECONDS;
else
_nanoseconds = seconds * NANO_PER_SEC + nanoseconds;
Janik Zikovsky
committed
}
Gigg, Martyn Anthony
committed
//------------------------------------------------------------------------------------------------
/** Construct a time from the number of seconds and nanoseconds since Jan 1,
* 1990.
Janik Zikovsky
committed
* @param seconds :: seconds since Jan 1, 1990.
* @param nanoseconds :: nanoseconds to add to the number of seconds
Janik Zikovsky
committed
*/
DateAndTime::DateAndTime(const int32_t seconds, const int32_t nanoseconds) {
const int64_t seconds_64bit = static_cast<int64_t>(seconds);
if (seconds_64bit >= MAX_SECONDS)
Janik Zikovsky
committed
_nanoseconds = MAX_NANOSECONDS;
else if (seconds_64bit <= MIN_SECONDS)
Janik Zikovsky
committed
_nanoseconds = MIN_NANOSECONDS;
else
_nanoseconds =
seconds_64bit * NANO_PER_SEC + static_cast<int64_t>(nanoseconds);
Janik Zikovsky
committed
}
//===========================================================================================
//===========================================================================================
//------------------------------------------------------------------------------------------------
/** Get the time as a boost::posix_time::ptime.
* @return a boost::posix_time::ptime.
*/
boost::posix_time::ptime DateAndTime::to_ptime() const {
return DateAndTimeHelpers::GPS_EPOCH + durationFromNanoseconds(_nanoseconds);
Janik Zikovsky
committed
}
//------------------------------------------------------------------------------------------------
/** Sets the date and time using a boost::posix_time::ptime
*
Janik Zikovsky
committed
* @param _ptime :: boost::posix_time::ptime date and time.
Janik Zikovsky
committed
*/
void DateAndTime::set_from_ptime(boost::posix_time::ptime _ptime) {
if (_ptime.is_special()) {
Janik Zikovsky
committed
// --- SPECIAL VALUES! ----
if (_ptime.is_infinity() || _ptime.is_pos_infinity())
_nanoseconds = MAX_NANOSECONDS;
if (_ptime.is_neg_infinity())
_nanoseconds = MIN_NANOSECONDS;
if (_ptime.is_not_a_date_time())
_nanoseconds = MIN_NANOSECONDS;
} else {
_nanoseconds =
nanosecondsFromDuration(_ptime - DateAndTimeHelpers::GPS_EPOCH);
// Check for overflow
if (_nanoseconds < 0) {
if (_ptime.date().year() >= 1990) {
// nanoseconds is negative despite the year being higher than 1990
Janik Zikovsky
committed
// ... means overflow occured
this->setToMaximum();
Janik Zikovsky
committed
}
} else if (_nanoseconds > 0) {
if (_ptime.date().year() < 1990) {
// Nanoseconds is positive but the year is below 1990 = it should be
// negative!
this->setToMinimum();
Janik Zikovsky
committed
}
}
}
}
//===========================================================================================
//========================== time_t support
//=================================================
Janik Zikovsky
committed
//===========================================================================================
//------------------------------------------------------------------------------------------------
/** Sets the date and time using a std::time_t
*
Janik Zikovsky
committed
* @param _timet :: std::time_t to set to
Janik Zikovsky
committed
*/
void DateAndTime::set_from_time_t(std::time_t _timet) {
this->set_from_ptime(boost::posix_time::from_time_t(_timet));
Janik Zikovsky
committed
}
//------------------------------------------------------------------------------------------------
/** Get the time as a std::time_t
* @return a std::time_t
*/
std::time_t DateAndTime::to_time_t() const {
Janik Zikovsky
committed
std::tm as_tm = boost::posix_time::to_tm(this->to_ptime());
std::time_t to_time_t = DateAndTimeHelpers::utc_mktime(&as_tm);
Janik Zikovsky
committed
return to_time_t;
}
//-----------------------------------------------------------------------------------------------
/** Convert a DateAndTime object to a std::tm time structure, using whatever
* time zone in the
Janik Zikovsky
committed
* dateAndtime (should be UTC) .
*/
std::tm DateAndTime::to_tm() const {
Janik Zikovsky
committed
std::tm as_tm;
Janik Zikovsky
committed
as_tm = boost::posix_time::to_tm(this->to_ptime());
} catch (std::out_of_range &) { // MW 26/10 - above code throws on some
// setups, create "dummy" date object
Janik Zikovsky
committed
as_tm.tm_year = 0;
as_tm.tm_mon = 0;
as_tm.tm_mday = 1;
as_tm.tm_hour = 0;
as_tm.tm_min = 0;
as_tm.tm_sec = 0;
as_tm.tm_wday = 0;
as_tm.tm_yday = 0;
as_tm.tm_isdst = 0;
}
return as_tm;
}
Janik Zikovsky
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Convert a DateAndTime object (in UTC) to a std::tm time structure, using the
* locat time zone.
Janik Zikovsky
committed
*/
std::tm DateAndTime::to_localtime_tm() const {
// Get the time_t in UTC
Janik Zikovsky
committed
std::time_t my_time_t = this->to_time_t();
std::tm result;
Janik Zikovsky
committed
Janik Zikovsky
committed
#ifdef _WIN32
Janik Zikovsky
committed
localtime_s(&result, &my_time_t);
Janik Zikovsky
committed
#else
Janik Zikovsky
committed
localtime_r(&my_time_t, &result);
Janik Zikovsky
committed
#endif
Janik Zikovsky
committed
return result;
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Convert a DateAndTime object (in UTC time) to std::time_t, in the LOCAL
* timezone.
Janik Zikovsky
committed
*/
std::time_t DateAndTime::to_localtime_t() const {
Janik Zikovsky
committed
std::tm as_tm = this->to_tm();
std::time_t to_time_t = mktime(&as_tm);
Janik Zikovsky
committed
return to_time_t;
}
//------------------------------------------------------------------------------------------------
/** Sets the date and time to the maximum allowed value */
void DateAndTime::setToMaximum() {
Janik Zikovsky
committed
_nanoseconds = MAX_NANOSECONDS; //+2^62, or around the year 2136
}
/** Sets the date and time to the minimum allowed value */
void DateAndTime::setToMinimum() {
Janik Zikovsky
committed
_nanoseconds = MIN_NANOSECONDS; //-2^62, or around the year 1843
}
/** Return the maximum time possible */
DateAndTime DateAndTime::maximum() { return DateAndTime(MAX_NANOSECONDS); }
Janik Zikovsky
committed
/** Return the minimum time possible */
DateAndTime DateAndTime::minimum() { return DateAndTime(MIN_NANOSECONDS); }
Janik Zikovsky
committed
/// A default date and time to use when time is not specified
const DateAndTime DateAndTime::defaultTime() {
Janik Zikovsky
committed
return DateAndTime("1970-01-01T00:00:00");
}
//------------------------------------------------------------------------------------------------
/** Sets the date and time using an ISO8601-formatted string
*
Janik Zikovsky
committed
* @param str :: ISO8601 format string: "yyyy-mm-ddThh:mm:ss[Z+-]tz:tz"
* @param displayLogs :: flag to indiciate if the logs should be displayed
Janik Zikovsky
committed
*/
void DateAndTime::setFromISO8601(const std::string str, bool displayLogs) {
Janik Zikovsky
committed
std::string time = str;
Janik Zikovsky
committed
// 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 << std::endl;
}
Janik Zikovsky
committed
bool positive_offset = true;
time_duration tz_offset = boost::posix_time::seconds(0);
const size_t nCharT = time.find('T');
if (nCharT != std::string::npos) {
// Take out the T, for later
time[nCharT] = ' ';
Janik Zikovsky
committed
// 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);
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
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));
Janik Zikovsky
committed
}
}
}
// 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.");
Janik Zikovsky
committed
}
//------------------------------------------------------------------------------------------------
/** Return the date and time as a simple string,
* for example, "19-Feb-2010 11:23:34.456000000"
* @return date-time formatted as a simple string
Janik Zikovsky
committed
*/
std::string DateAndTime::toSimpleString() const {
Janik Zikovsky
committed
return boost::posix_time::to_simple_string(this->to_ptime());
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Return the date and time as a string, using formatting of strftime().
* Default format gives "1990-Jan-02 03:04:05"
* @param format : format for strftime(). Default "%Y-%b-%d %H:%M:%S"
* @return date as string, formatted as requested
Janik Zikovsky
committed
*/
std::string DateAndTime::toFormattedString(const std::string format) const {
char buffer[25];
Janik Zikovsky
committed
std::tm date_as_tm = this->to_tm();
strftime(buffer, 25, format.c_str(), &date_as_tm);
Janik Zikovsky
committed
return std::string(buffer);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Return the date and time as an ISO8601-formatted string
* @return The ISO8601 string
Janik Zikovsky
committed
*/
std::string DateAndTime::toISO8601String() const {
return boost::posix_time::to_iso_extended_string(to_ptime());
Janik Zikovsky
committed
}
Janik Zikovsky
committed
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Get the year of this date.
* @return the year
Janik Zikovsky
committed
*/
int DateAndTime::year() const { return to_ptime().date().year(); }
Janik Zikovsky
committed
Janik Zikovsky
committed
/** Get the month of this date.
* @return the month
int DateAndTime::month() const { return to_ptime().date().month(); }
Janik Zikovsky
committed
/** Get the day (of the month) of this date.
* @return the day
*/
int DateAndTime::day() const { return to_ptime().date().day(); }
Janik Zikovsky
committed
/** Get the hour (0-24) of this time.
* @return the hour
*/
int DateAndTime::hour() const { return to_ptime().time_of_day().hours(); }
Janik Zikovsky
committed
/** Get the minute (0-60) of this time.
* @return the minute
*/
int DateAndTime::minute() const { return to_ptime().time_of_day().minutes(); }
Janik Zikovsky
committed
/** Get the seconds (0-60) of this time.
* @return the second
Janik Zikovsky
committed
*/
int DateAndTime::second() const { return to_ptime().time_of_day().seconds(); }
Janik Zikovsky
committed
/** Get the nanoseconds (remainder, < 1 second) of this time.
* @return the nanoseconds
*/
int DateAndTime::nanoseconds() const {
return static_cast<int>(_nanoseconds % NANO_PER_SEC);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Return the total # of nanoseconds since the epoch */
int64_t DateAndTime::totalNanoseconds() const { return this->_nanoseconds; }
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** == operator
Janik Zikovsky
committed
* @param rhs :: DateAndTime to compare
Janik Zikovsky
committed
* @return true if equals
*/
bool DateAndTime::operator==(const DateAndTime &rhs) const {
Janik Zikovsky
committed
return _nanoseconds == rhs._nanoseconds;
}
/** == operator for boost::posix_time::ptime
Janik Zikovsky
committed
* @param rhs :: boost::posix_time::ptime to compare
Janik Zikovsky
committed
* @return true if equals
*/
bool DateAndTime::operator==(const boost::posix_time::ptime &rhs) const {
Janik Zikovsky
committed
return this->to_ptime() == rhs;
}
/**
* Compare to another DateAndTime within the specified tolerance.
* @param rhs DateAndTime to compare
* @param tol the number of nanoseconds they can differ by
* @return true if equal within tolerances.
*/
bool DateAndTime::equals(const DateAndTime &rhs, const int64_t tol) const {
int64_t diff = _nanoseconds - rhs._nanoseconds;
if (diff > tol)
return false;
return false;
return true;
}
Janik Zikovsky
committed
/** != operator
Janik Zikovsky
committed
* @param rhs :: DateAndTime to compare
Janik Zikovsky
committed
* @return true if not equals
*/
bool DateAndTime::operator!=(const DateAndTime &rhs) const {
Janik Zikovsky
committed
return _nanoseconds != rhs._nanoseconds;
Janik Zikovsky
committed
}
Janik Zikovsky
committed
/** < operator
Janik Zikovsky
committed
* @param rhs :: DateAndTime to compare
Janik Zikovsky
committed
* @return true if less than
*/
bool DateAndTime::operator<(const DateAndTime &rhs) const {
Janik Zikovsky
committed
return _nanoseconds < rhs._nanoseconds;
}
Janik Zikovsky
committed
Janik Zikovsky
committed
/** <= operator
Janik Zikovsky
committed
* @param rhs :: DateAndTime to compare
Janik Zikovsky
committed
* @return true if less than or equals
Janik Zikovsky
committed
*/
bool DateAndTime::operator<=(const DateAndTime &rhs) const {
Janik Zikovsky
committed
return _nanoseconds <= rhs._nanoseconds;
}
Janik Zikovsky
committed
Janik Zikovsky
committed
/** > operator
Janik Zikovsky
committed
* @param rhs :: DateAndTime to compare
Janik Zikovsky
committed
* @return true if greater than
*/
bool DateAndTime::operator>(const DateAndTime &rhs) const {
Janik Zikovsky
committed
return _nanoseconds > rhs._nanoseconds;
}
Janik Zikovsky
committed
Janik Zikovsky
committed
/** >= operator
Janik Zikovsky
committed
* @param rhs :: DateAndTime to compare
Janik Zikovsky
committed
* @return true if greater than or equals
*/
bool DateAndTime::operator>=(const DateAndTime &rhs) const {
Janik Zikovsky
committed
return _nanoseconds >= rhs._nanoseconds;
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** + operator to add time.
Janik Zikovsky
committed
* @param nanosec :: number of nanoseconds to add
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime DateAndTime::operator+(const int64_t nanosec) const {
Janik Zikovsky
committed
return DateAndTime(_nanoseconds + nanosec);
Janik Zikovsky
committed
/** += operator to add time.
Janik Zikovsky
committed
* @param nanosec :: number of nanoseconds to add
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime &DateAndTime::operator+=(const int64_t nanosec) {
Janik Zikovsky
committed
_nanoseconds += nanosec;
if (_nanoseconds > MAX_NANOSECONDS)
_nanoseconds = MAX_NANOSECONDS;
else if (_nanoseconds < MIN_NANOSECONDS)
_nanoseconds = MIN_NANOSECONDS;
Janik Zikovsky
committed
return *this;
Janik Zikovsky
committed
/** - operator to subtract time.
Janik Zikovsky
committed
* @param nanosec :: number of nanoseconds to subtract
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime DateAndTime::operator-(const int64_t nanosec) const {
Janik Zikovsky
committed
return DateAndTime(_nanoseconds - nanosec);
}
Janik Zikovsky
committed
Janik Zikovsky
committed
/** -= operator to subtract time.
Janik Zikovsky
committed
* @param nanosec :: number of nanoseconds to subtract
Janik Zikovsky
committed
* @return modified DateAndTime.
Janik Zikovsky
committed
*/
DateAndTime &DateAndTime::operator-=(const int64_t nanosec) {
Janik Zikovsky
committed
_nanoseconds -= nanosec;
if (_nanoseconds > MAX_NANOSECONDS)
_nanoseconds = MAX_NANOSECONDS;
else if (_nanoseconds < MIN_NANOSECONDS)
_nanoseconds = MIN_NANOSECONDS;
Janik Zikovsky
committed
return *this;
Janik Zikovsky
committed
}
Janik Zikovsky
committed
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** + operator to add time.
Janik Zikovsky
committed
* @param td :: time_duration to add
Janik Zikovsky
committed
* @return modified DateAndTime.
Janik Zikovsky
committed
*/
DateAndTime DateAndTime::operator+(const time_duration &td) const {
return this->operator+(nanosecondsFromDuration(td));
Janik Zikovsky
committed
}
Janik Zikovsky
committed
/** += operator to add time.
Janik Zikovsky
committed
* @param td :: time_duration to add
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime &DateAndTime::operator+=(const time_duration &td) {
return this->operator+=(nanosecondsFromDuration(td));
Janik Zikovsky
committed
}
Janik Zikovsky
committed
Janik Zikovsky
committed
/** - operator to subtract time.
Janik Zikovsky
committed
* @param td :: time_duration to subtract
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime DateAndTime::operator-(const time_duration &td) const {
return this->operator-(nanosecondsFromDuration(td));
Janik Zikovsky
committed
}
/** -= operator to subtract time.
Janik Zikovsky
committed
* @param td :: time_duration to subtract
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime &DateAndTime::operator-=(const time_duration &td) {
return this->operator-=(nanosecondsFromDuration(td));
Janik Zikovsky
committed
}
//------------------------------------------------------------------------------------------------
/** + operator to add time.
Janik Zikovsky
committed
* @param sec :: duration to add
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime DateAndTime::operator+(const double sec) const {
return this->operator+(nanosecondsFromSeconds(sec));
Janik Zikovsky
committed
}
/** += operator to add time.
Janik Zikovsky
committed
* @param sec :: duration to add
Janik Zikovsky
committed
* @return modified DateAndTime.
Janik Zikovsky
committed
*/
DateAndTime &DateAndTime::operator+=(const double sec) {
return this->operator+=(nanosecondsFromSeconds(sec));
Janik Zikovsky
committed
}
Janik Zikovsky
committed
/** - operator to subtract time.
Janik Zikovsky
committed
* @param sec :: duration to subtract
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime DateAndTime::operator-(const double sec) const {
return this->operator-(nanosecondsFromSeconds(sec));
Janik Zikovsky
committed
}
/** -= operator to subtract time.
Janik Zikovsky
committed
* @param sec :: duration to subtract
Janik Zikovsky
committed
* @return modified DateAndTime.
*/
DateAndTime &DateAndTime::operator-=(const double sec) {
return this->operator-=(nanosecondsFromSeconds(sec));
Janik Zikovsky
committed
}
//------------------------------------------------------------------------------------------------
/** Subtract two times.
* @param rhs object on right of operation
Janik Zikovsky
committed
* @return a time_duration
*/
time_duration DateAndTime::operator-(const DateAndTime &rhs) const {
Janik Zikovsky
committed
return this->to_ptime() - rhs.to_ptime();
}
//------------------------------------------------------------------------------------------------
/** Returns the current DateAndTime, in UTC time, with microsecond precision
* @return the current time.
*/
DateAndTime DateAndTime::getCurrentTime() {
Janik Zikovsky
committed
return DateAndTime(boost::posix_time::microsec_clock::universal_time());
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/**
* Return the number of seconds in a time_duration, as a double, including
* fractional seconds.
Janik Zikovsky
committed
*/
double DateAndTime::secondsFromDuration(time_duration duration) {
Janik Zikovsky
committed
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
// Nanosecond resolution
return static_cast<double>(duration.total_nanoseconds()) / 1e9;
Janik Zikovsky
committed
#else
// Microsecond resolution
return static_cast<double>(duration.total_microseconds()) / 1e6;
#endif
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/**
* Return a time_duration object with the given the number of seconds
Janik Zikovsky
committed
*/
time_duration DateAndTime::durationFromSeconds(double duration) {
long secs = static_cast<long>(duration);
Janik Zikovsky
committed
// Limit the seconds to the range of long (avoid overflows)
Janik Zikovsky
committed
if (duration >= std::numeric_limits<int>::max())
return boost::posix_time::time_duration(boost::posix_time::max_date_time);
Janik Zikovsky
committed
else if (duration <= std::numeric_limits<int>::min())
return boost::posix_time::time_duration(boost::posix_time::min_date_time);
Janik Zikovsky
committed
typedef boost::posix_time::time_res_traits::sec_type sec_type;
Janik Zikovsky
committed
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
// Nanosecond resolution
long fracsecs = long(1e9 * fmod(duration, 1.0));
return boost::posix_time::time_duration(0, 0, static_cast<sec_type>(secs),
fracsecs);
Janik Zikovsky
committed
#else
// Microsecond resolution
long fracsecs = long(1e6 * fmod(duration, 1.0));
return boost::posix_time::time_duration(0, 0, static_cast<sec_type>(secs),
fracsecs);
Janik Zikovsky
committed
#endif
Janik Zikovsky
committed
}
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/** time duration in nanoseconds. Duration is limited to
* MAX_NANOSECONDS and MIN_NANOSECONDS to avoid overflows.
Janik Zikovsky
committed
* @param td :: time_duration instance.
* @return an int64 of the number of nanoseconds
Janik Zikovsky
committed
*/
int64_t DateAndTime::nanosecondsFromDuration(const time_duration &td) {
Janik Zikovsky
committed
int64_t nano;
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
// Nanosecond resolution
nano = td.total_nanoseconds();
Janik Zikovsky
committed
#else
// Microsecond resolution
nano = (td.total_microseconds() * 1000);
Janik Zikovsky
committed
#endif
// Use these limits to avoid integer overflows
if (nano > MAX_NANOSECONDS)
Janik Zikovsky
committed
return MAX_NANOSECONDS;
else if (nano < MIN_NANOSECONDS)
return MIN_NANOSECONDS;
else
return nano;
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/** time duration from nanoseconds
Janik Zikovsky
committed
* @param dur :: duration in nanoseconds, as an int
Janik Zikovsky
committed
* @return a time_duration type
*/
time_duration DateAndTime::durationFromNanoseconds(int64_t dur) {
Janik Zikovsky
committed
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
// Nanosecond resolution
return boost::posix_time::time_duration(0, 0, 0, dur);
Janik Zikovsky
committed
#else
// Microsecond resolution
return boost::posix_time::time_duration(0, 0, 0, dur / 1000);
Janik Zikovsky
committed
#endif
}
Michael Whitty
committed
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Nanoseconds from seconds, with limits
Janik Zikovsky
committed
* @param sec :: duration in seconds, as a double
Janik Zikovsky
committed
* @return int64 of the number of nanoseconds
*/
int64_t DateAndTime::nanosecondsFromSeconds(double sec) {
Janik Zikovsky
committed
double nano = sec * 1e9;
// Use these limits to avoid integer overflows
if (nano > MAX_NANOSECONDS)
Janik Zikovsky
committed
return MAX_NANOSECONDS;
else if (nano < MIN_NANOSECONDS)
return MIN_NANOSECONDS;
else
return int64_t(nano);
}
//-----------------------------------------------------------------------------------------------
/** Static method to create a vector of DateAndTime objects
* using a start time and seconds offset. To speed things up,
* no limit checking is performed!
*
* @param start :: DateAndTime at 0.
* @param seconds :: a vector of doubles of the number of seconds.
* @param out :: reference to a vector that will be filled with DateAndTime's
*/
void DateAndTime::createVector(const DateAndTime start,
const std::vector<double> &seconds,
std::vector<DateAndTime> &out) {
int64_t startnano = start._nanoseconds;
size_t num = seconds.size();
out.resize(num);
size_t i = 0;
for (auto it = seconds.begin(); it != seconds.end(); ++it) {
out[i]._nanoseconds =
startnano + static_cast<int64_t>((*it) * 1000000000.0);
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
/** Check if a string is iso8601 format.
*
* @param str :: string to check
* @return true if the string conforms to ISO 860I, false otherwise.
*/
bool DateAndTime::stringIsISO8601(const std::string &str) {
Poco::DateTime dt;
int tz_diff;
return Poco::DateTimeParser::tryParse(Poco::DateTimeFormat::ISO8601_FORMAT,
str, dt, tz_diff);
}
std::ostream &operator<<(std::ostream &stream, const DateAndTime &t) {
stream << t.toSimpleString();
return stream;
Janik Zikovsky
committed
TimeInterval::TimeInterval(const DateAndTime &from, const DateAndTime &to)
: m_begin(from) {
if (to > from)
m_end = to;
else
m_end = from;
}
/** Returns an intersection of this interval with \a ti
Janik Zikovsky
committed
@param ti :: Time interval
Janik Zikovsky
committed
@return A valid time interval if this interval intersects with \a ti or
TimeInterval TimeInterval::intersection(const TimeInterval &ti) const {
if (!isValid() || !ti.isValid())
return TimeInterval();
DateAndTime t1 = begin();
if (ti.begin() > t1)
t1 = ti.begin();
DateAndTime t2 = end();
if (ti.end() < t2)
t2 = ti.end();
return t1 < t2 ? TimeInterval(t1, t2) : TimeInterval();
/// String representation of the begin time
std::string TimeInterval::begin_str() const {
Janik Zikovsky
committed
return boost::posix_time::to_simple_string(this->m_begin.to_ptime());
}
/// String representation of the end time
std::string TimeInterval::end_str() const {
Janik Zikovsky
committed
return boost::posix_time::to_simple_string(this->m_end.to_ptime());
std::ostream &operator<<(std::ostream &s,
const Mantid::Kernel::TimeInterval &t) {
s << t.begin().toSimpleString() << " - " << t.end().toSimpleString();
return s;
}
Janik Zikovsky
committed