Newer
Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
/*
* DateAndTimeTest.h
*
* Created on: Aug 30, 2010
* Author: janik
*/
#ifndef DATEANDTIMETEST_H_
#define DATEANDTIMETEST_H_
#include "MantidKernel/DateAndTime.h"
#include "MantidKernel/System.h"
#include <cxxtest/TestSuite.h>
#include <sstream>
#include <sys/stat.h>
using namespace Mantid;
using namespace Mantid::Kernel;
using std::runtime_error;
using std::size_t;
using std::vector;
//==========================================================================================
class DateAndTimeTest : public CxxTest::TestSuite {
void test_constructors_and_set() {
// Expected will be Jan 2, 1990, at 00:01:02
boost::posix_time::ptime expected =
boost::posix_time::from_iso_string(std::string("19900102T000102.345"));
Janik Zikovsky
committed
DateAndTime d;
// 1day, 1 minute, 2 seconds, 0.345 seconds = 86462345000000 nanosec
// Nanoseconds constructor
d = DateAndTime(int64_t(86462345000000LL));
Janik Zikovsky
committed
TS_ASSERT_EQUALS(d, expected);
Janik Zikovsky
committed
d = DateAndTime(86462, 345000000);
TS_ASSERT_EQUALS(d, expected);
d = DateAndTime(86462.0, 345000000.0);
TS_ASSERT_EQUALS(d, expected);
Janik Zikovsky
committed
d = DateAndTime(expected);
TS_ASSERT_EQUALS(d, expected);
Janik Zikovsky
committed
d = DateAndTime("1990-01-02T00:01:02.345");
TS_ASSERT_EQUALS(d, expected);
d.setFromISO8601("1990-01-02T00:01:02.345");
Janik Zikovsky
committed
TS_ASSERT_EQUALS(d, expected);
Janik Zikovsky
committed
d = DateAndTime("1990-01-02 00:01:02.345");
TS_ASSERT_EQUALS(d, expected);
d.setFromISO8601("1990-01-02 00:01:02.345");
Janik Zikovsky
committed
TS_ASSERT_EQUALS(d, expected);
}
void test_constructor_fails_invalid_string() {
TS_ASSERT_THROWS(DateAndTime("invalid time string"),
const std::invalid_argument &);
const std::invalid_argument &);
TS_ASSERT_THROWS(DateAndTime("2017-09-27T 07:03:49+00:00"),
const std::invalid_argument &);
void test_limits_on_construction() {
// direct nanoseconds constructor
DateAndTime a, b, c;
Gigg, Martyn Anthony
committed
a = DateAndTime(int64_t(6917529027641081856LL));
TS_ASSERT_EQUALS(a, DateAndTime::maximum());
Gigg, Martyn Anthony
committed
a = DateAndTime(int64_t(-6917529027641081856LL));
// Double constructor
TS_ASSERT_EQUALS(a, DateAndTime::minimum());
Janik Zikovsky
committed
a = DateAndTime(1e20, 0.2);
TS_ASSERT_EQUALS(a, DateAndTime::maximum());
Janik Zikovsky
committed
a = DateAndTime(-1e20, 0.2);
TS_ASSERT_EQUALS(a, DateAndTime::minimum());
Janik Zikovsky
committed
Gigg, Martyn Anthony
committed
int64_t li = 1000000000000000000LL;
int64_t li2 = 2000000LL;
TS_ASSERT_EQUALS(a, DateAndTime::maximum());
TS_ASSERT_EQUALS(a, DateAndTime::minimum());
Janik Zikovsky
committed
a = DateAndTime("2490-01-02 00:01:02.345");
TS_ASSERT_EQUALS(a, DateAndTime::maximum());
Janik Zikovsky
committed
a = DateAndTime("1600-01-02 00:01:02.345");
TS_ASSERT_EQUALS(a, DateAndTime::minimum());
boost::posix_time::ptime p;
p = boost::posix_time::from_iso_string("24000102T000102");
a = DateAndTime(p);
TS_ASSERT_EQUALS(a, DateAndTime::maximum());
p = boost::posix_time::from_iso_string("16000102T000102");
a = DateAndTime(p);
TS_ASSERT_EQUALS(a, DateAndTime::minimum());
// time_t and int constructors can't overflow on 32-bits at least
Janik Zikovsky
committed
}
Janik Zikovsky
committed
DateAndTime a;
a = DateAndTime("1990-01-02 03:04:05.678");
TS_ASSERT_EQUALS(a.year(), 1990);
TS_ASSERT_EQUALS(a.month(), 1);
TS_ASSERT_EQUALS(a.day(), 2);
TS_ASSERT_EQUALS(a.hour(), 3);
TS_ASSERT_EQUALS(a.minute(), 4);
TS_ASSERT_EQUALS(a.second(), 5);
TS_ASSERT_EQUALS(a.nanoseconds(), 678000000);
Janik Zikovsky
committed
}
void test_comparison_operators() {
DateAndTime a, b, c, d;
Janik Zikovsky
committed
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
c = DateAndTime("1990-01-02 00:01:02.345");
d = DateAndTime("1990-01-02 00:00:02.000000001");
TS_ASSERT(a < b);
TS_ASSERT(b > a);
TS_ASSERT(a <= b);
TS_ASSERT(b >= a);
TS_ASSERT(a == a);
TS_ASSERT(b == b);
TS_ASSERT(b == c);
TS_ASSERT(a != b);
// intentionally different to confirm the tolerance check works
TS_ASSERT(a != d);
TS_ASSERT(a.equals(d));
Janik Zikovsky
committed
boost::posix_time::ptime p;
p = boost::posix_time::from_iso_string("19900102T000002.000");
TS_ASSERT(a == p);
TS_ASSERT(b != p);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
DateAndTime a;
a = DateAndTime("1990-01-02 03:04:05.678");
std::string s = a.toSimpleString();
TS_ASSERT_EQUALS(s.substr(0, 20), "1990-Jan-02 03:04:05");
TS_ASSERT_EQUALS(a.toFormattedString(), "1990-Jan-02 03:04:05");
TS_ASSERT_EQUALS(a.toFormattedString("%Y-%m-%d"), "1990-01-02");
TS_ASSERT_EQUALS(a.toISO8601String(), "1990-01-02T03:04:05.678000000");
Janik Zikovsky
committed
}
Janik Zikovsky
committed
DateAndTime a;
a = DateAndTime("1990-01-02 00:01:02.345");
int64_t nanosec = a.totalNanoseconds();
// 1day, 1 minute, 2 seconds, 0.345 seconds = 86462345000000 nanosec
TS_ASSERT_EQUALS(nanosec, int64_t(86462345000000LL));
}
Janik Zikovsky
committed
Janik Zikovsky
committed
DateAndTime a;
std::ostringstream message;
a = DateAndTime("1990-01-02 03:04:05.678");
message << a;
TS_ASSERT_EQUALS(message.str(), a.toSimpleString());
std::ostringstream message2;
message2 << a << "\n";
TS_ASSERT_EQUALS(message2.str(), a.toSimpleString() + "\n");
Janik Zikovsky
committed
}
void test_subtraction_of_times() {
DateAndTime a, b, c;
Janik Zikovsky
committed
boost::posix_time::ptime p;
time_duration td;
a = DateAndTime("1990-01-02 00:01:02.345");
b = DateAndTime("1990-01-02 00:00:02.000");
td = a - b;
TS_ASSERT_EQUALS(
td, DateAndTime::durationFromNanoseconds(int64_t(60345000000LL)));
Janik Zikovsky
committed
a = DateAndTime("1990-01-02 00:01:02.345");
p = boost::posix_time::from_iso_string("19900102T000002.000");
// boost ptime gets converted to ptime implicitely
td = a - p;
TS_ASSERT_EQUALS(
td, DateAndTime::durationFromNanoseconds(int64_t(60345000000LL)));
Janik Zikovsky
committed
}
void test_subtraction_of_times_limits() {
DateAndTime a, b, c;
boost::posix_time::ptime p;
time_duration td;
a = DateAndTime("2200-01-02 00:01:02.345");
b = DateAndTime("1800-01-02 00:01:02.345");
td = a - b;
// The difference won't be correct, but it is positive and ~2**62
// nanoseconds
TS_ASSERT_LESS_THAN(4.6e9, DateAndTime::secondsFromDuration(td));
td = b - a;
// The difference won't be correct, but it is negative
TS_ASSERT_LESS_THAN(DateAndTime::secondsFromDuration(td), -4.6e9);
void test_addition_and_subtraction_operators_nanoseconds_as_int() {
DateAndTime a, b, c;
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
Gigg, Martyn Anthony
committed
c = a + int64_t(60345000000LL);
Gigg, Martyn Anthony
committed
a += int64_t(60345000000LL);
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
Gigg, Martyn Anthony
committed
c = b - int64_t(60345000000LL);
Gigg, Martyn Anthony
committed
b -= int64_t(60345000000LL);
Janik Zikovsky
committed
void test_addition_and_subtraction_operators_time_duration() {
DateAndTime a, b, c;
Janik Zikovsky
committed
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
c = a + DateAndTime::durationFromNanoseconds(int64_t(60345000000LL));
a += DateAndTime::durationFromNanoseconds(int64_t(60345000000LL));
Janik Zikovsky
committed
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
c = b - DateAndTime::durationFromNanoseconds(int64_t(60345000000LL));
b -= DateAndTime::durationFromNanoseconds(int64_t(60345000000LL));
Janik Zikovsky
committed
}
void test_addition_and_subtraction_operators_double() {
DateAndTime a, b, c;
Janik Zikovsky
committed
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
c = a + 60.345;
Janik Zikovsky
committed
a += 60.345;
Janik Zikovsky
committed
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
c = b - 60.345;
Janik Zikovsky
committed
b -= 60.345;
Janik Zikovsky
committed
}
void test_limits_on_addition_and_subtraction() {
DateAndTime a, b, c;
Janik Zikovsky
committed
a = DateAndTime("1990-01-02 00:00:02.000");
b = a + 1e20;
TS_ASSERT_EQUALS(b, DateAndTime::maximum());
Janik Zikovsky
committed
b = a - 1e20;
TS_ASSERT_LESS_THAN(b.year(), 1900);
Janik Zikovsky
committed
a = DateAndTime("1989-01-02 00:00:02.000");
b = a - 1e20;
TS_ASSERT_EQUALS(b, DateAndTime::minimum());
Janik Zikovsky
committed
b = a + 1e20;
TS_ASSERT_LESS_THAN(2000, b.year());
Janik Zikovsky
committed
}
void test_dataSizes() {
// Must occupy 8 bytes!
TS_ASSERT_EQUALS(sizeof(DateAndTime), 8);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
DateAndTime t;
std::time_t current = time(nullptr);
t.set_from_time_t(current);
// if (cur.day() < 28) // Annoying bug at the end of a month
{ TS_ASSERT_EQUALS(current, t.to_time_t()); }
Janik Zikovsky
committed
}
void testCurrentTime() {
// Use the c-method to get current (local) time
std::time_t current_t = DateAndTime::getCurrentTime().to_time_t();
std::tm *current = gmtime(¤t_t);
// std::cout << "UTC time is " << current->tm_hour << "h" << current->tm_min
// << "\n";
// Compare
TS_ASSERT(current->tm_year >=
110); // Wrote this in 2010, so the year must be > 110
int hour = 12;
std::time_t rawtime;
std::time(&rawtime); // current time will be overwritten
std::tm *timeinfo = new std::tm;
timeinfo->tm_isdst = -1;
timeinfo->tm_year = 108;
timeinfo->tm_mon = 1;
timeinfo->tm_mday = 29;
timeinfo->tm_hour = hour;
timeinfo->tm_min = 0;
timeinfo->tm_sec = 0;
// Convert to time_t but assuming the tm is specified in UTC time.
std::time_t utc_time_t = Mantid::Kernel::DateAndTime::utc_mktime(timeinfo);
// This will be the local time
std::time_t local_time_t = std::mktime(timeinfo);
Janik Zikovsky
committed
Janik Zikovsky
committed
DateAndTime utc_time;
utc_time.set_from_time_t(utc_time_t);
// Timezone offset in hours (sorry, newfoundland and labrador - half time
// zones are crazy! )
int tz_offset = static_cast<int>(difftime(utc_time_t, local_time_t) / 3600);
Janik Zikovsky
committed
std::tm utc_tm = utc_time.to_tm();
TS_ASSERT_EQUALS(utc_tm.tm_hour, hour);
Janik Zikovsky
committed
std::tm local_tm = utc_time.to_localtime_tm();
TS_ASSERT_EQUALS(local_tm.tm_hour, hour + tz_offset);
// Now the time_t conversion, UTC time
TS_ASSERT_EQUALS(utc_time.to_time_t(), utc_time_t);
// Now the time_t conversion, local time
TS_ASSERT_EQUALS(utc_time.to_localtime_t(), local_time_t);
// Now the string
TS_ASSERT_EQUALS(utc_time.toSimpleString(), "2008-Feb-29 12:00:00");
void test_ISO8601_string_with_timezones() {
// Time without timezone : UTC assumed
Janik Zikovsky
committed
DateAndTime time_no_tz = DateAndTime("2010-03-24T14:12:51.562");
DateAndTime time_no_fraction = DateAndTime("2010-03-24T14:12:51");
Janik Zikovsky
committed
// The conversion should handle the fraction
TS_ASSERT_DELTA(Mantid::Kernel::DateAndTime::secondsFromDuration(
time_no_tz - time_no_fraction),
0.562, 0.0005);
Janik Zikovsky
committed
Janik Zikovsky
committed
DateAndTime time_z = DateAndTime("2010-03-24T14:12:51.562Z");
// Positive time offset (also a fraction like Newfoundland (crazy newfies ;)
// )
Janik Zikovsky
committed
DateAndTime time_positive_tz = DateAndTime("2010-03-24T19:42:51.562+05:30");
DateAndTime time_positive_tz2 = DateAndTime("2010-03-24T16:12:51.562+02");
Janik Zikovsky
committed
DateAndTime time_negative_tz = DateAndTime("2010-03-24T10:12:51.562-04:00");
DateAndTime time_negative_tz2 = DateAndTime("2010-03-24T06:12:51.562-08");
Janik Zikovsky
committed
// Now check the time zone difference
TS_ASSERT_DELTA(
Mantid::Kernel::DateAndTime::secondsFromDuration(time_no_tz - time_z),
0.0, 1e-4);
TS_ASSERT_DELTA(Mantid::Kernel::DateAndTime::secondsFromDuration(
time_no_tz - time_positive_tz),
0.0, 1e-4);
TS_ASSERT_DELTA(Mantid::Kernel::DateAndTime::secondsFromDuration(
time_no_tz - time_negative_tz),
0.0, 1e-4);
TS_ASSERT_DELTA(Mantid::Kernel::DateAndTime::secondsFromDuration(
time_no_tz - time_positive_tz2),
0.0, 1e-4);
TS_ASSERT_DELTA(Mantid::Kernel::DateAndTime::secondsFromDuration(
time_no_tz - time_negative_tz2),
0.0, 1e-4);
void testDurations() {
time_duration onesec = time_duration(0, 0, 1, 0);
TS_ASSERT_EQUALS(DateAndTime::secondsFromDuration(onesec), 1.0);
Janik Zikovsky
committed
onesec = DateAndTime::durationFromSeconds(1.0);
TS_ASSERT_EQUALS(DateAndTime::secondsFromDuration(onesec), 1.0);
Janik Zikovsky
committed
time_duration td = DateAndTime::durationFromSeconds(1e-6);
TS_ASSERT_DELTA(DateAndTime::secondsFromDuration(td), 1e-6, 1e-9);
Janik Zikovsky
committed
Janik Zikovsky
committed
DateAndTime dt = DateAndTime(0);
DateAndTime dt2 = dt + td;
TS_ASSERT_DELTA(DateAndTime::secondsFromDuration(dt2 - dt), 1e-6, 1e-9);
Janik Zikovsky
committed
td = DateAndTime::durationFromSeconds(12.345);
TS_ASSERT_DELTA(DateAndTime::secondsFromDuration(td), 12.345, 1e-9);
Janik Zikovsky
committed
dt2 = dt + DateAndTime::durationFromSeconds(123.5e-3);
TS_ASSERT_DELTA(DateAndTime::secondsFromDuration(dt2 - dt), 123.5e-3, 1e-9);
Janik Zikovsky
committed
dt2 = dt + DateAndTime::durationFromSeconds(15.2345);
TS_ASSERT_DELTA(DateAndTime::secondsFromDuration(dt2 - dt), 15.2345, 1e-9);
Janik Zikovsky
committed
dt2 = dt + DateAndTime::durationFromSeconds(152.345);
TS_ASSERT_DELTA(DateAndTime::secondsFromDuration(dt2 - dt), 152.345, 1e-9);
Janik Zikovsky
committed
}
/* Ensure that exceptions thrown by boost date_time conversions are caught
where they
Janik Zikovsky
committed
may cause problems. */
Janik Zikovsky
committed
boost::posix_time::ptime time(boost::posix_time::not_a_date_time);
Janik Zikovsky
committed
DateAndTime dt(time);
TS_ASSERT_THROWS(boost::posix_time::to_tm(time), const std::out_of_range &);
TS_ASSERT_THROWS_NOTHING(dt.to_tm());
Janik Zikovsky
committed
}
void test_duration_limits() {
DateAndTime a, b, c, d;
Janik Zikovsky
committed
time_duration td;
Janik Zikovsky
committed
a = DateAndTime("2010-03-24T14:12:51.562");
Janik Zikovsky
committed
// Only about 290 years time difference are supported (2^63 nanoseconds)!
Janik Zikovsky
committed
b = DateAndTime("2300-03-24T14:12:51.562");
Janik Zikovsky
committed
c = a + td;
Janik Zikovsky
committed
}
void test_duration_from_seconds_Extremes() {
time_duration onesec = time_duration(0, 0, 1, 0);
Janik Zikovsky
committed
time_duration extreme;
extreme = DateAndTime::durationFromSeconds(1e20);
Janik Zikovsky
committed
TS_ASSERT_LESS_THAN(onesec, extreme);
extreme = DateAndTime::durationFromSeconds(-1e20);
Janik Zikovsky
committed
TS_ASSERT_LESS_THAN(extreme, onesec);
}
DateAndTime a = DateAndTime("1990-01-02 03:04:05.000");
std::vector<double> secs{1.0, 2.0, 0.5, -3.0};
std::vector<DateAndTime> times;
DateAndTime::createVector(a, secs, times);
TS_ASSERT_EQUALS(times.size(), secs.size());
TS_ASSERT_EQUALS(times[0], DateAndTime("1990-01-02 03:04:06.000"));
TS_ASSERT_EQUALS(times[1], DateAndTime("1990-01-02 03:04:07.000"));
TS_ASSERT_EQUALS(times[2], DateAndTime("1990-01-02 03:04:05.500"));
TS_ASSERT_EQUALS(times[3], DateAndTime("1990-01-02 03:04:02.000"));
};
#endif /* DATEANDTIMETEST_H_ */