Newer
Older
/*
* DateAndTimeTest.h
*
* Created on: Aug 30, 2010
* Author: janik
*/
#ifndef DATEANDTIMETEST_H_
#define DATEANDTIMETEST_H_
#include <cxxtest/TestSuite.h>
#include "MantidKernel/DateAndTime.h"
#include "MantidKernel/System.h"
#include <sys/stat.h>
#include <time.h>
Janik Zikovsky
committed
#include <sstream>
using namespace Mantid;
using namespace Mantid::Kernel;
using std::runtime_error;
using std::size_t;
using std::vector;
using std::cout;
using std::endl;
//==========================================================================================
class DateAndTimeTest: public CxxTest::TestSuite
{
public:
Janik Zikovsky
committed
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"));
DateAndTime d;
//1day, 1 minute, 2 seconds, 0.345 seconds = 86462345000000 nanosec
//Nanoseconds constructor
Gigg, Martyn Anthony
committed
d = DateAndTime( int64_t(86462345000000LL) );
Janik Zikovsky
committed
TS_ASSERT_EQUALS(d, expected);
//Second, nanosec constructor
d = DateAndTime(86462, 345000000);
TS_ASSERT_EQUALS(d, expected);
d = DateAndTime(86462.0, 345000000.0);
TS_ASSERT_EQUALS(d, expected);
//ptime
d = DateAndTime(expected);
TS_ASSERT_EQUALS(d, expected);
//string
d = DateAndTime("1990-01-02T00:01:02.345");
TS_ASSERT_EQUALS(d, expected);
d.set_from_ISO8601_string("1990-01-02T00:01:02.345");
TS_ASSERT_EQUALS(d, expected);
//string with a space
d = DateAndTime("1990-01-02 00:01:02.345");
TS_ASSERT_EQUALS(d, expected);
d.set_from_ISO8601_string("1990-01-02 00:01:02.345");
TS_ASSERT_EQUALS(d, expected);
}
void test_limits_on_construction()
{
//direct nanoseconds constructor
Janik Zikovsky
committed
DateAndTime a,b,c;
Gigg, Martyn Anthony
committed
a = DateAndTime(int64_t(6917529027641081856LL));
Janik Zikovsky
committed
TS_ASSERT_EQUALS( a, DateAndTime::maximum());
Gigg, Martyn Anthony
committed
a = DateAndTime(int64_t(-6917529027641081856LL));
Janik Zikovsky
committed
TS_ASSERT_EQUALS( a, DateAndTime::minimum());
a = DateAndTime(1e20, 0.2);
TS_ASSERT_EQUALS( a, DateAndTime::maximum());
a = DateAndTime(-1e20, 0.2);
TS_ASSERT_EQUALS( a, DateAndTime::minimum());
Gigg, Martyn Anthony
committed
int64_t li = 1000000000000000000LL;
int64_t li2 = 2000000LL;
a = DateAndTime(li, li2);
TS_ASSERT_EQUALS( a, DateAndTime::maximum());
a = DateAndTime(-li, li2);
TS_ASSERT_EQUALS( a, DateAndTime::minimum());
//String constructors
Janik Zikovsky
committed
a = DateAndTime("2490-01-02 00:01:02.345");
TS_ASSERT_EQUALS( a, DateAndTime::maximum());
a = DateAndTime("1600-01-02 00:01:02.345");
TS_ASSERT_EQUALS( a, DateAndTime::minimum());
//ptime constructor
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
}
void test_year_month_etc()
{
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;
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");
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 );
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
void test_to_string()
{
DateAndTime a;
a = DateAndTime("1990-01-02 03:04:05.678");
std::string s = a.to_simple_string();
TS_ASSERT_EQUALS( s.substr(0,20), "1990-Jan-02 03:04:05");
TS_ASSERT_EQUALS( a.to_string(), "1990-Jan-02 03:04:05");
TS_ASSERT_EQUALS( a.to_string("%Y-%m-%d"), "1990-01-02");
TS_ASSERT_EQUALS( a.to_ISO8601_string(), "1990-01-02T03:04:05");
Janik Zikovsky
committed
}
Janik Zikovsky
committed
void test_to_int64()
{
DateAndTime a;
a = DateAndTime("1990-01-02 00:01:02.345");
int64_t nanosec = a.total_nanoseconds();
//1day, 1 minute, 2 seconds, 0.345 seconds = 86462345000000 nanosec
TS_ASSERT_EQUALS( nanosec, int64_t(86462345000000LL) );
}
Janik Zikovsky
committed
void test_stream_operator()
{
DateAndTime a;
std::ostringstream message;
a = DateAndTime("1990-01-02 03:04:05.678");
message << a;
TS_ASSERT_EQUALS( message.str(), a.to_simple_string() );
std::ostringstream message2;
message2 << a << "\n";
TS_ASSERT_EQUALS( message2.str(), a.to_simple_string()+"\n" );
Janik Zikovsky
committed
}
void test_subtraction_of_times()
{
DateAndTime a,b,c;
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;
Gigg, Martyn Anthony
committed
TS_ASSERT_EQUALS( td, DateAndTime::duration_from_nanoseconds(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;
Gigg, Martyn Anthony
committed
TS_ASSERT_EQUALS( td, DateAndTime::duration_from_nanoseconds(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::seconds_from_duration(td) );
td = b-a;
//The difference won't be correct, but it is negative
TS_ASSERT_LESS_THAN( DateAndTime::seconds_from_duration(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);
TS_ASSERT_EQUALS( a, b);
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);
TS_ASSERT_EQUALS( b, a);
}
Janik Zikovsky
committed
void test_addition_and_subtraction_operators_time_duration()
{
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 + DateAndTime::duration_from_nanoseconds(int64_t(60345000000LL));
Janik Zikovsky
committed
TS_ASSERT_EQUALS( c, b);
Gigg, Martyn Anthony
committed
a += DateAndTime::duration_from_nanoseconds(int64_t(60345000000LL));
Janik Zikovsky
committed
TS_ASSERT_EQUALS( a, b);
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
Gigg, Martyn Anthony
committed
c = b - DateAndTime::duration_from_nanoseconds(int64_t(60345000000LL));
Janik Zikovsky
committed
TS_ASSERT_EQUALS( c, a);
Gigg, Martyn Anthony
committed
b -= DateAndTime::duration_from_nanoseconds(int64_t(60345000000LL));
Janik Zikovsky
committed
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
TS_ASSERT_EQUALS( b, a);
}
void test_addition_and_subtraction_operators_double()
{
DateAndTime a,b,c;
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
c = a + 60.345;
TS_ASSERT_EQUALS( c, b);
a += 60.345;
TS_ASSERT_EQUALS( a, b);
a = DateAndTime("1990-01-02 00:00:02.000");
b = DateAndTime("1990-01-02 00:01:02.345");
c = b - 60.345;
TS_ASSERT_EQUALS( c, a);
b -= 60.345;
TS_ASSERT_EQUALS( b, a);
}
void test_limits_on_addition_and_subtraction()
{
DateAndTime a,b,c;
a = DateAndTime("1990-01-02 00:00:02.000");
b = a + 1e20;
TS_ASSERT_EQUALS( b, DateAndTime::maximum());
b = a - 1e20;
TS_ASSERT_LESS_THAN( b.year(), 1900);
a = DateAndTime("1989-01-02 00:00:02.000");
b = a - 1e20;
TS_ASSERT_EQUALS( b, DateAndTime::minimum());
b = a + 1e20;
TS_ASSERT_LESS_THAN( 2000, b.year());
}
Janik Zikovsky
committed
void test_dataSizes()
{
//Must occupy 8 bytes!
Janik Zikovsky
committed
TS_ASSERT_EQUALS( sizeof( DateAndTime ), 8 );
}
void test_time_t_support()
{
DateAndTime cur = DateAndTime::get_current_time();
Janik Zikovsky
committed
DateAndTime t;
std::time_t current = time (NULL);
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
}
Janik Zikovsky
committed
void testCurrentTime()
{
//Use the c-method to get current (local) time
Janik Zikovsky
committed
std::time_t current_t = DateAndTime::get_current_time().to_time_t() ;
std::tm * current = gmtime( ¤t_t );
Janik Zikovsky
committed
//std::cout << "UTC time is " << current->tm_hour << "h" << current->tm_min << "\n";
Janik Zikovsky
committed
TS_ASSERT( current->tm_year >= 110 ); //Wrote this in 2010, so the year must be > 110
Janik Zikovsky
committed
void test_timezones()
{
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.
Janik Zikovsky
committed
std::time_t utc_time_t = Mantid::Kernel::DateAndTimeHelpers::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);
//Get tm in localtime
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
Janik Zikovsky
committed
TS_ASSERT_EQUALS( utc_time.to_time_t(), utc_time_t);
//Now the time_t conversion, local time
Janik Zikovsky
committed
TS_ASSERT_EQUALS( utc_time.to_localtime_t(), local_time_t);
Janik Zikovsky
committed
TS_ASSERT_EQUALS( utc_time.to_simple_string(), "2008-Feb-29 12:00:00");
Michael Whitty
committed
Janik Zikovsky
committed
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
Janik Zikovsky
committed
TS_ASSERT_DELTA( Mantid::Kernel::DateAndTime::seconds_from_duration( time_no_tz-time_no_fraction ), 0.562, 0.0005);
Janik Zikovsky
committed
//ZULU specified
Janik Zikovsky
committed
DateAndTime time_z = DateAndTime("2010-03-24T14:12:51.562Z");
Janik Zikovsky
committed
//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
//Negative time offset
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
Janik Zikovsky
committed
TS_ASSERT_DELTA( Mantid::Kernel::DateAndTime::seconds_from_duration( time_no_tz-time_z ), 0.0, 1e-4);
TS_ASSERT_DELTA( Mantid::Kernel::DateAndTime::seconds_from_duration( time_no_tz-time_positive_tz ), 0.0, 1e-4);
TS_ASSERT_DELTA( Mantid::Kernel::DateAndTime::seconds_from_duration( time_no_tz-time_negative_tz ), 0.0, 1e-4);
TS_ASSERT_DELTA( Mantid::Kernel::DateAndTime::seconds_from_duration( time_no_tz-time_positive_tz2 ), 0.0, 1e-4);
TS_ASSERT_DELTA( Mantid::Kernel::DateAndTime::seconds_from_duration( time_no_tz-time_negative_tz2 ), 0.0, 1e-4);
Janik Zikovsky
committed
void testDurations()
{
time_duration onesec = time_duration(0,0,1,0);
Janik Zikovsky
committed
TS_ASSERT_EQUALS( DateAndTime::seconds_from_duration(onesec), 1.0 );
Janik Zikovsky
committed
onesec = DateAndTime::duration_from_seconds(1.0);
Janik Zikovsky
committed
TS_ASSERT_EQUALS( DateAndTime::seconds_from_duration(onesec), 1.0 );
Janik Zikovsky
committed
time_duration td = DateAndTime::duration_from_seconds(1e-6);
Janik Zikovsky
committed
TS_ASSERT_DELTA( DateAndTime::seconds_from_duration(td), 1e-6, 1e-9 );
Janik Zikovsky
committed
//Now difference between dates
Janik Zikovsky
committed
DateAndTime dt = DateAndTime(0);
DateAndTime dt2 = dt + td;
TS_ASSERT_DELTA( DateAndTime::seconds_from_duration(dt2-dt), 1e-6, 1e-9 );
Janik Zikovsky
committed
td = DateAndTime::duration_from_seconds(12.345);
Janik Zikovsky
committed
TS_ASSERT_DELTA( DateAndTime::seconds_from_duration(td), 12.345, 1e-9 );
Janik Zikovsky
committed
dt2 = dt + DateAndTime::duration_from_seconds(123.5e-3);
Janik Zikovsky
committed
TS_ASSERT_DELTA( DateAndTime::seconds_from_duration(dt2-dt), 123.5e-3, 1e-9 );
Janik Zikovsky
committed
dt2 = dt + DateAndTime::duration_from_seconds(15.2345);
Janik Zikovsky
committed
TS_ASSERT_DELTA( DateAndTime::seconds_from_duration(dt2-dt), 15.2345, 1e-9 );
Janik Zikovsky
committed
dt2 = dt + DateAndTime::duration_from_seconds(152.345);
Janik Zikovsky
committed
TS_ASSERT_DELTA( DateAndTime::seconds_from_duration(dt2-dt), 152.345, 1e-9 );
Janik Zikovsky
committed
}
Janik Zikovsky
committed
Janik Zikovsky
committed
/* Ensure that exceptions thrown by boost date_time conversions are caught where they
may cause problems. */
void testNotADateTime()
{
boost::posix_time::ptime time(boost::posix_time::not_a_date_time);
Janik Zikovsky
committed
DateAndTime dt(time);
Janik Zikovsky
committed
TS_ASSERT_THROWS(std::tm tm = boost::posix_time::to_tm(time), std::out_of_range);
Janik Zikovsky
committed
TS_ASSERT_THROWS_NOTHING(std::tm tm2 = dt.to_tm());
Janik Zikovsky
committed
}
Janik Zikovsky
committed
void test_duration_limits()
Janik Zikovsky
committed
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
td = b-a;
c = a + td;
TS_ASSERT_EQUALS( c, b);
}
void test_duration_from_seconds_Extremes()
{
time_duration onesec = time_duration(0,0,1,0);
time_duration extreme;
extreme = DateAndTime::duration_from_seconds(1e20);
//Output value is positive
Janik Zikovsky
committed
TS_ASSERT_LESS_THAN(onesec, extreme);
extreme = DateAndTime::duration_from_seconds(-1e20);
//Output value is negative
Janik Zikovsky
committed
TS_ASSERT_LESS_THAN(extreme, onesec);
}
void test_Vector()
{
DateAndTime a = DateAndTime("1990-01-02 03:04:05.000");
std::vector<double> secs;
secs.push_back(1.0);
secs.push_back(2.0);
secs.push_back(0.5);
secs.push_back(-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"));
void test_string_isISO8601()
{
TS_ASSERT( DateAndTime::string_isISO8601("1990-01-02 03:04:02.000") );
TS_ASSERT( DateAndTime::string_isISO8601("1990-01-02T03:04:02.000") );
TS_ASSERT( DateAndTime::string_isISO8601("1990-01-02T03:04:02.000+05:30") );
TS_ASSERT( DateAndTime::string_isISO8601("1990-01-02 03:04") );
TS_ASSERT( DateAndTime::string_isISO8601("1990-01-02") );
TS_ASSERT( DateAndTime::string_isISO8601("1822-01-02") );
TS_ASSERT(!DateAndTime::string_isISO8601("January 1, 2345") );
TS_ASSERT(!DateAndTime::string_isISO8601("2010-31-56") );
TS_ASSERT(!DateAndTime::string_isISO8601("1990-01-02 45:92:22") );
}
};
#endif /* DATEANDTIMETEST_H_ */