Newer
Older
Janik Zikovsky
committed
#include <time.h>
namespace Mantid
{
namespace Kernel
{
Janik Zikovsky
committed
/// Max allowed nanoseconds in the time; 2^62-1
static int64_t MAX_NANOSECONDS = 4611686018427387903LL;
Janik Zikovsky
committed
/// Max allowed seconds in the time
static int64_t MAX_SECONDS = 4611686017LL;
Janik Zikovsky
committed
/// Min allowed nanoseconds in the time; -2^62+1
static int64_t MIN_NANOSECONDS = -4611686018427387903LL;
Janik Zikovsky
committed
/// Min allowed seconds in the time
static 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
53
54
55
56
57
58
59
60
61
62
63
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
/// 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->set_from_ISO8601_string(ISO8601_string);
}
//------------------------------------------------------------------------------------------------
/** 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 = nano;
}
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 = seconds * 1e9 + nanoseconds;;
}
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 = seconds * 1e9 + nanoseconds;;
}
//===========================================================================================
//===========================================================================================
//------------------------------------------------------------------------------------------------
/** 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 + duration_from_nanoseconds(_nanoseconds);
}
//------------------------------------------------------------------------------------------------
/** 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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
*/
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 = nanoseconds_from_duration(_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
// ... means overflow occured
this->set_to_maximum();
}
}
else if (_nanoseconds > 0)
{
if (_ptime.date().year() < 1990)
{
//Nanoseconds is positive but the year is below 1990 = it should be negative!
this->set_to_minimum();
}
}
}
}
//===========================================================================================
//========================== 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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
/** 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::set_to_maximum()
{
_nanoseconds = MAX_NANOSECONDS; //+2^62, or around the year 2136
}
/** Sets the date and time to the minimum allowed value */
void DateAndTime::set_to_minimum()
{
_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::set_from_ISO8601_string(const std::string str)
Janik Zikovsky
committed
{
//Make a copy
std::string time = str;
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
size_t n = time.find('T');
if (n != std::string::npos)
Janik Zikovsky
committed
{
//Take out the T, for later
Janik Zikovsky
committed
time[n] = ' ';
Janik Zikovsky
committed
410
411
412
413
414
415
416
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
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
//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
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 );
}
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::to_simple_string() const
{
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::to_string(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 without fractional seconds.
* @return string
*/
std::string DateAndTime::to_ISO8601_string() const
{
return this->to_string("%Y-%m-%dT%H:%M:%S");
}
Janik Zikovsky
committed
Janik Zikovsky
committed
////------------------------------------------------------------------------------------------------
Janik Zikovsky
committed
///** Stream operator
// */
//std::ostream& DateAndTime::operator<< (std::ostream& stream, const DateAndTime & obj)
Janik Zikovsky
committed
//{
// stream << obj->to_simple_string();
// return stream;
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 (_nanoseconds % 1000000000);
}
Janik Zikovsky
committed
//------------------------------------------------------------------------------------------------
/** Return the total # of nanoseconds since the epoch */
int64_t DateAndTime::total_nanoseconds() 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
{
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;
}
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
{
Janik Zikovsky
committed
return this->operator +(nanoseconds_from_duration(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 +=(nanoseconds_from_duration(td));
}
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 -(nanoseconds_from_duration(td));
}
/** -= 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 -=(nanoseconds_from_duration(td));
}
//------------------------------------------------------------------------------------------------
/** + 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 +(nanoseconds_from_seconds(sec));
}
/** += 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
{
Janik Zikovsky
committed
return this->operator +=(nanoseconds_from_seconds(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 -(nanoseconds_from_seconds(sec));
}
/** -= 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 -=(nanoseconds_from_seconds(sec));
}
//------------------------------------------------------------------------------------------------
/** 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::get_current_time()
{
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
*/
Janik Zikovsky
committed
double DateAndTime::seconds_from_duration(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;
#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
*/
Janik Zikovsky
committed
time_duration DateAndTime::duration_from_seconds(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 );
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
// Nanosecond resolution
long fracsecs = long ( 1e9 * fmod(duration, 1.0) );
return boost::posix_time::time_duration(0,0,secs, fracsecs);
#else
// Microsecond resolution
long fracsecs = long ( 1e6 * fmod(duration, 1.0) );
return boost::posix_time::time_duration(0,0,secs, fracsecs);
#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
*/
Janik Zikovsky
committed
int64_t DateAndTime::nanoseconds_from_duration(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();
#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
*/
Janik Zikovsky
committed
time_duration DateAndTime::duration_from_nanoseconds(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::nanoseconds_from_seconds(double sec)
{
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);
std::vector<double>::const_iterator it;
size_t i = 0;
for(it = seconds.begin(); it != seconds.end(); it++)
{
out[i]._nanoseconds = startnano + static_cast<int64_t>( (*it) * 1000000000.0 );
Janik Zikovsky
committed
Janik Zikovsky
committed
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
{
if (!isValid() || !ti.isValid()) return TimeInterval();
Janik Zikovsky
committed
DateAndTime t1 = begin();
if (ti.begin() > t1) t1 = ti.begin();
Janik Zikovsky
committed
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());
Janik Zikovsky
committed