Newer
Older
Janik Zikovsky
committed
#include <time.h>
#include <Poco/DateTime.h>
#include <Poco/DateTimeFormat.h>
#include <Poco/DateTimeParser.h>
#include <boost/date_time/posix_time/posix_time_config.hpp>
#include <ostream>
#include <ctime>
namespace Mantid
{
namespace Kernel
{
Logger g_log("DateAndTime");
Janik Zikovsky
committed
/// Max allowed nanoseconds in the time; 2^62-1
int64_t MAX_NANOSECONDS = 4611686018427387903LL;
Janik Zikovsky
committed
/// Max allowed seconds in the time
int64_t MAX_SECONDS = 4611686017LL;
Janik Zikovsky
committed
/// Min allowed nanoseconds in the time; -2^62+1
int64_t MIN_NANOSECONDS = -4611686018427387903LL;
Janik Zikovsky
committed
/// Min allowed seconds in the time
int64_t MIN_SECONDS = -4611686017LL;
}
Janik Zikovsky
committed
namespace DateAndTimeHelpers
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 )
{
#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
//Unix implementation
return gmtime_r(clock, result);
#endif
}
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/// 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
/// Released to the public domain.
time_t utc_mktime(struct tm *utctime)
{
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);
if( result == (time_t)-1 )
return (time_t)-1;
Janik Zikovsky
committed
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 ||
Janik Zikovsky
committed
check.tm_mon != utctime->tm_mon ||
check.tm_mday != utctime->tm_mday ||
check.tm_hour != utctime->tm_hour ||
Janik Zikovsky
committed
check.tm_min != utctime->tm_min ) )
Janik Zikovsky
committed
{
tmp.tm_min += utctime->tm_min - check.tm_min;
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);
if( result == (time_t)-1 )
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;
Janik Zikovsky
committed
//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.
counter++;
Janik Zikovsky
committed
}
return result;
}
Janik Zikovsky
committed
} //namespace DateAndTimeHelpers
//------------------------------------------------------------------------------------------------
/** Default, empty constructor */
DateAndTime::DateAndTime() : _nanoseconds(0)
{}
//------------------------------------------------------------------------------------------------
/** Construct a date from nanoseconds.
Janik Zikovsky
committed
* @param total_nanoseconds :: nanoseconds since Jan 1, 1990 (our epoch).
Janik Zikovsky
committed
*/
Gigg, Martyn Anthony
committed
DateAndTime::DateAndTime(const int64_t total_nanoseconds)
Janik Zikovsky
committed
{
Janik Zikovsky
committed
//Make sure that you cannot construct a date that is beyond the limits...
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,
* and the time is optional, as is the time-zone specification.
*/
DateAndTime::DateAndTime(const std::string ISO8601_string) : _nanoseconds(0)
{
this->setFromISO8601(ISO8601_string);
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)
{
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)
{
double nano = seconds * 1e9 + nanoseconds;
//Limit times
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
//------------------------------------------------------------------------------------------------
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
*/
Gigg, Martyn Anthony
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 = static_cast<int64_t>(seconds * 1000000000LL + nanoseconds);
Janik Zikovsky
committed
}
Gigg, Martyn Anthony
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
*/
Gigg, Martyn Anthony
committed
DateAndTime::DateAndTime(const int32_t seconds, const int32_t nanoseconds)
Janik Zikovsky
committed
{
if (seconds >= MAX_SECONDS)
_nanoseconds = MAX_NANOSECONDS;
else if (seconds <= MIN_SECONDS)
_nanoseconds = MIN_NANOSECONDS;
else
_nanoseconds = static_cast<int64_t>(seconds * 1000000000LL + 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())
{
// --- 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);
Janik Zikovsky
committed
//Check for overflow
if (_nanoseconds < 0)
{
if (_ptime.date().year() >= 1990)
{
//nanoseconds is negative despite the year being higher than 1990
// ... 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 =================================================
//===========================================================================================
//------------------------------------------------------------------------------------------------
/** 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 ) );
}
//------------------------------------------------------------------------------------------------
/** Get the time as a std::time_t
* @return a std::time_t
*/
std::time_t DateAndTime::to_time_t() const
{
std::tm as_tm = boost::posix_time::to_tm(this->to_ptime());
std::time_t to_time_t = DateAndTimeHelpers::utc_mktime( &as_tm );
return to_time_t;
}
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/** Convert a DateAndTime object to a std::tm time structure, using whatever time zone in the
* dateAndtime (should be UTC) .
*/
Janik Zikovsky
committed
std::tm DateAndTime::to_tm() const
{
Janik Zikovsky
committed
std::tm as_tm;
try
{
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
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.
*/
std::tm DateAndTime::to_localtime_tm() const
{
//Get the time_t in UTC
std::time_t my_time_t = this->to_time_t();
std::tm result;
Janik Zikovsky
committed
Janik Zikovsky
committed
#ifdef _WIN32
//Windows version
localtime_s(&result, &my_time_t);
Janik Zikovsky
committed
#else
Janik Zikovsky
committed
//Unix implementation
localtime_r(&my_time_t, &result);
Janik Zikovsky
committed
#endif
Janik Zikovsky
committed
return result;
}
Janik Zikovsky
committed
//-----------------------------------------------------------------------------------------------
Janik Zikovsky
committed
/** Convert a DateAndTime object (in UTC time) to std::time_t, in the LOCAL timezone.
*/
std::time_t DateAndTime::to_localtime_t() const
{
std::tm as_tm = this->to_tm();
std::time_t to_time_t = mktime( &as_tm );
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
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
{
_nanoseconds = MIN_NANOSECONDS; //-2^62, or around the year 1843
}
/** Return the maximum time possible */
DateAndTime DateAndTime::maximum()
{
return DateAndTime(MAX_NANOSECONDS);
}
/** Return the minimum time possible */
DateAndTime DateAndTime::minimum()
{
return DateAndTime(MIN_NANOSECONDS);
}
/// A default date and time to use when time is not specified
const DateAndTime DateAndTime::defaultTime()
{
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"
Janik Zikovsky
committed
*/
void DateAndTime::setFromISO8601(const std::string str)
Janik Zikovsky
committed
{
//Make a copy
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)
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';
g_log.warning() << " corrected to " << time << std::endl;
Janik Zikovsky
committed
//Default of no timezone offset
bool positive_offset = true;
time_duration tz_offset = boost::posix_time::seconds(0);
Janik Zikovsky
committed
//Replace "T" with a space
const size_t nCharT = time.find('T');
if (nCharT != std::string::npos)
Janik Zikovsky
committed
{
//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)
Janik Zikovsky
committed
{
//Found a Z. Remove it, and no timezone fix
time = time.substr(0, nCharZ);
Janik Zikovsky
committed
}
else
{
//Look for a + or - indicating time zone offset
n_plus = time.find('+', nCharT);
n_minus = time.find('-', nCharT);
Janik Zikovsky
committed
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 assume the time has not been given
if(time.find(":") == std::string::npos)
throw std::invalid_argument("Error interpreting string '" + str + "' as a date/time.");
Janik Zikovsky
committed
if (positive_offset)
//The timezone is + so we need to subtract the hours
Janik Zikovsky
committed
this->set_from_ptime( boost::posix_time::time_from_string(time) - tz_offset );
Janik Zikovsky
committed
else
//The timezone is - so we need to ADD the hours
Janik Zikovsky
committed
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
}
Janik Zikovsky
committed
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
Janik Zikovsky
committed
{
Janik Zikovsky
committed
char buffer [25];
std::tm date_as_tm = this->to_tm();
strftime (buffer, 25, format.c_str(), &date_as_tm);
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
Janik Zikovsky
committed
{
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
*/
Janik Zikovsky
committed
int DateAndTime::year() const
Janik Zikovsky
committed
{
Janik Zikovsky
committed
return to_ptime().date().year();
Janik Zikovsky
committed
}
Janik Zikovsky
committed
/** Get the month of this date.
* @return the month
Janik Zikovsky
committed
int DateAndTime::month() const
Janik Zikovsky
committed
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
*/
Janik Zikovsky
committed
int DateAndTime::second() const
Janik Zikovsky
committed
{
Janik Zikovsky
committed
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 % 1000000000);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Return the total # of nanoseconds since the epoch */
int64_t DateAndTime::totalNanoseconds() const
Janik Zikovsky
committed
{
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
{
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
{
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;
else if (diff < -1*tol)
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
{
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
{
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
*/
Janik Zikovsky
committed
bool DateAndTime::operator<=(const DateAndTime& rhs) const
Janik Zikovsky
committed
{
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
{
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
{
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;
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
{
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
*/
Janik Zikovsky
committed
DateAndTime& DateAndTime::operator-=(const int64_t nanosec)
Janik Zikovsky
committed
{
Janik Zikovsky
committed
_nanoseconds -= nanosec;
if (_nanoseconds > MAX_NANOSECONDS) _nanoseconds = MAX_NANOSECONDS;
else if (_nanoseconds < MIN_NANOSECONDS) _nanoseconds = MIN_NANOSECONDS;
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
*/
Janik Zikovsky
committed
DateAndTime DateAndTime::operator+(const time_duration& td) const
Janik Zikovsky
committed
{
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
*/
Janik Zikovsky
committed
DateAndTime& DateAndTime::operator+=(const double sec)
Janik Zikovsky
committed
{
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
{
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
{
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)
Janik Zikovsky
committed
{
Janik Zikovsky
committed
long secs = static_cast<long>( duration );
//Limit the seconds to the range of long (avoid overflows)
if (duration >= std::numeric_limits<int>::max())
return boost::posix_time::time_duration( boost::posix_time::max_date_time );
else if (duration <= std::numeric_limits<int>::min())
return boost::posix_time::time_duration( boost::posix_time::min_date_time );
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
//-----------------------------------------------------------------------------------------------
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
{
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);
#endif
//Use these limits to avoid integer overflows
if (nano >MAX_NANOSECONDS)
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);
#else
// Microsecond resolution
return boost::posix_time::time_duration(0,0,0,dur/1000);
#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)
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
an empty interval otherwise.
*/
TimeInterval TimeInterval::intersection(const TimeInterval& ti)const