C++ Utilities  5.0.0
Useful C++ classes and routines such as argument parser, IO and conversion utilities
chronotests.cpp
Go to the documentation of this file.
1 #include "../chrono/datetime.h"
2 #include "../chrono/format.h"
3 #include "../chrono/period.h"
4 #include "../chrono/timespan.h"
5 #include "../conversion/conversionexception.h"
6 #include "../tests/testutils.h"
7 
8 #include <cppunit/TestFixture.h>
9 #include <cppunit/extensions/HelperMacros.h>
10 
11 #include <cmath>
12 #include <iostream>
13 
14 using namespace std;
15 using namespace CppUtilities;
16 using namespace CppUtilities::Literals;
17 
18 using namespace CPPUNIT_NS;
19 
20 // compile-time checks for DateTime class
21 static_assert(DateTime().isNull(), "isNull()");
22 static_assert(DateTime(1).totalTicks() == 1, "construction with ticks");
23 static_assert(DateTime(2) == DateTime(2), "operator ==");
24 static_assert(DateTime(2) != DateTime(3), "operator !=");
25 static_assert(DateTime(2) < DateTime(3), "operator <");
26 static_assert(DateTime(3) > DateTime(2), "operator >");
27 static_assert(DateTime::eternity().isEternity() && !DateTime().isEternity(), "isEternity()");
28 static constexpr auto dateFromUnixEpoch(
29  DateTime::unixEpochStart() + TimeSpan::fromHours(1) + TimeSpan::fromMinutes(2) + TimeSpan::fromSeconds(3.1256789));
30 static_assert(dateFromUnixEpoch.dayOfWeek() == DayOfWeek::Thursday, "dayOfWeek()");
31 static_assert(dateFromUnixEpoch.hour() == 1, "hour()");
32 static_assert(dateFromUnixEpoch.minute() == 2, "minute()");
33 static_assert(dateFromUnixEpoch.second() == 3, "second()");
34 static_assert(dateFromUnixEpoch.millisecond() == 125, "millisecond()");
35 static_assert(dateFromUnixEpoch.microsecond() == 678, "microsecond()");
36 static_assert(dateFromUnixEpoch.nanosecond() == 900, "nanosecond()");
37 static_assert(dateFromUnixEpoch.isSameDay(DateTime::unixEpochStart()), "isSameDay()");
38 static_assert(!dateFromUnixEpoch.isSameDay(DateTime::unixEpochStart() + TimeSpan::fromHours(24)), "!isSameDay()");
39 
40 // compile-time checks for TimeSpan class
41 static_assert(TimeSpan().isNull(), "isNull()");
42 static_assert(TimeSpan(1).totalTicks() == 1, "construction with ticks");
43 static_assert(TimeSpan(-1).isNegative() && !TimeSpan(1).isNegative(), "isNegative()");
44 static_assert(TimeSpan::infinity().isInfinity() && !TimeSpan().isInfinity(), "isInfinity()");
45 static_assert(TimeSpan::negativeInfinity().isNegativeInfinity() && !TimeSpan().isNegativeInfinity(), "isNegativeInfinity()");
46 static_assert(TimeSpan::fromMilliseconds(1.0125).nanoseconds() == 500, "fromMilliseconds()/nanoseconds()");
47 static_assert(TimeSpan::fromMilliseconds(1.0125).microseconds() == 12, "fromMilliseconds()/microseconds()");
48 static_assert(TimeSpan::fromMilliseconds(1.0125).milliseconds() == 1, "fromMilliseconds()/milliseconds()");
49 static_assert(TimeSpan::fromSeconds(61).seconds() == 1, "fromSeconds()/seconds()");
50 static_assert(TimeSpan::fromSeconds(61).minutes() == 1, "fromSeconds()/minutes()");
51 static_assert(TimeSpan::fromMinutes(61).minutes() == 1, "fromMinutes()/minutes()");
52 static_assert(TimeSpan::fromHours(25).hours() == 1, "fromMinutes()/hours()");
53 static_assert(TimeSpan::fromDays(20.5).days() == 20, "fromDays()/days()");
54 static_assert(TimeSpan::fromMinutes(1.5).totalMicroseconds() == 90e6, "totalMicroseconds()");
55 static_assert(TimeSpan::fromMinutes(1.5).totalMilliseconds() == 90e3, "totalMilliseconds()");
56 static_assert(TimeSpan::fromMinutes(1.5).totalSeconds() == 90.0, "totalSeconds()");
57 static_assert(TimeSpan::fromHours(1.5).totalMinutes() == 90.0, "totalMinutes()");
58 static_assert(TimeSpan::fromDays(1.5).totalHours() == 36.0, "totalHours()");
59 static_assert(TimeSpan::fromDays(20.5).totalDays() == 20.5, "totalDays()");
60 
67 class ChronoTests : public TestFixture {
68  CPPUNIT_TEST_SUITE(ChronoTests);
69  CPPUNIT_TEST(testDateTime);
70  CPPUNIT_TEST(testTimeSpan);
71  CPPUNIT_TEST(testOperators);
72  CPPUNIT_TEST(testPeriod);
73  CPPUNIT_TEST(testHashing);
74  CPPUNIT_TEST_SUITE_END();
75 
76 public:
77  void setUp()
78  {
79  }
80  void tearDown()
81  {
82  }
83 
84  void testDateTime();
85  void testTimeSpan();
86  void testOperators();
87  void testPeriod();
88  void testHashing();
89 };
90 
92 
97 {
98  // test year(), month(), ...
99  CPPUNIT_ASSERT_EQUAL(DateTime::daysInMonth(2000, 2), 29);
100  CPPUNIT_ASSERT_EQUAL(DateTime::daysInMonth(2001, 2), 28);
101  CPPUNIT_ASSERT_EQUAL(DateTime::daysInMonth(2100, 2), 28);
102  const auto test1 = DateTime::fromDateAndTime(2012, 2, 29, 15, 34, 20, 33.0);
103  CPPUNIT_ASSERT_EQUAL(2012, test1.year());
104  CPPUNIT_ASSERT_EQUAL(2, test1.month());
105  CPPUNIT_ASSERT_EQUAL(29, test1.day());
106  CPPUNIT_ASSERT_EQUAL(15, test1.hour());
107  CPPUNIT_ASSERT_EQUAL(34, test1.minute());
108  CPPUNIT_ASSERT_EQUAL(20, test1.second());
109  CPPUNIT_ASSERT_EQUAL(33, test1.millisecond());
110  CPPUNIT_ASSERT_EQUAL(DayOfWeek::Wednesday, test1.dayOfWeek());
111  CPPUNIT_ASSERT_EQUAL((31 + 29), test1.dayOfYear());
112  CPPUNIT_ASSERT(test1.isLeapYear());
113  CPPUNIT_ASSERT(test1.isSameDay(test1 + TimeSpan::fromHours(8)));
114  CPPUNIT_ASSERT(!test1.isSameDay(test1 + TimeSpan::fromHours(9)));
115  CPPUNIT_ASSERT_EQUAL("Wed 2012-02-29 15:34:20.033"s, test1.toString(DateTimeOutputFormat::DateTimeAndShortWeekday));
116 
117  // test fromTimeStamp()
118  const auto fromTimeStampGmt = DateTime::fromTimeStampGmt(1453840331), fromTimeStamp = DateTime::fromTimeStamp(1453840331);
119  CPPUNIT_ASSERT_EQUAL("Tue 2016-01-26 20:32:11"s, fromTimeStampGmt.toString(DateTimeOutputFormat::DateTimeAndShortWeekday));
120  CPPUNIT_ASSERT(fabs((fromTimeStamp - fromTimeStampGmt).totalDays()) <= 1.0);
121  CPPUNIT_ASSERT_EQUAL(DateTime(), DateTime::fromTimeStamp(0));
122 
123  // test whether ConversionException() is thrown when invalid values are specified
124  CPPUNIT_ASSERT_THROW(DateTime::fromDate(0, 1, 1), ConversionException);
125  CPPUNIT_ASSERT_THROW(DateTime::fromDate(2012, 15, 1), ConversionException);
126  CPPUNIT_ASSERT_THROW(DateTime::fromDateAndTime(0, 2, 29, 15, 34, 20, 33), ConversionException);
127  CPPUNIT_ASSERT_THROW(DateTime::fromDateAndTime(2013, 2, 29, 15, 34, 20, 33), ConversionException);
128  CPPUNIT_ASSERT_THROW(DateTime::fromDateAndTime(2012, 2, 29, 15, 61, 20, 33), ConversionException);
129  CPPUNIT_ASSERT_THROW(DateTime::fromDateAndTime(2012, 4, 31, 15, 0, 20, 33), ConversionException);
130  CPPUNIT_ASSERT_THROW(DateTime::fromDateAndTime(2012, 3, 31, 15, 0, 61, 33), ConversionException);
131  CPPUNIT_ASSERT_THROW(DateTime::fromDateAndTime(2012, 1, 1, 61, 2, 1), ConversionException);
132  CPPUNIT_ASSERT_THROW(DateTime::fromDateAndTime(2012, 1, 1, 15, 2, 1, 2000.0), ConversionException);
133 
134  // test fromString()/toString()
135  CPPUNIT_ASSERT_EQUAL(test1, DateTime::fromString("2012-02-29 15:34:20.033"));
136  CPPUNIT_ASSERT_EQUAL_MESSAGE("surplus parts ignored", test1, DateTime::fromString("2012-02-29 15:34:20.033:12"));
137  CPPUNIT_ASSERT_EQUAL("2012-02-29 15:34:20.033"s, test1.toString(DateTimeOutputFormat::DateAndTime, false));
138  CPPUNIT_ASSERT_THROW(TimeSpan::fromString("2012-02-29 15:34:34:20.033"), ConversionException);
139  const auto test3 = DateTime::fromIsoString("2016-08-29T21:32:31.125+02:00");
140  CPPUNIT_ASSERT_EQUAL("2016-08-29T21:32:31.125+02:00"s, test3.first.toIsoString(test3.second));
141  CPPUNIT_ASSERT_THROW(DateTime::fromString("#"), ConversionException);
142  // test accuracy (of 100 nanoseconds)
143  const auto test4 = DateTime::fromIsoString("2017-08-23T19:40:15.985077682+02:30");
144  CPPUNIT_ASSERT_EQUAL(2.5, test4.second.totalHours());
145  CPPUNIT_ASSERT_EQUAL(15, test4.first.second());
146  CPPUNIT_ASSERT_EQUAL(985, test4.first.millisecond());
147  CPPUNIT_ASSERT_EQUAL(77, test4.first.microsecond());
148  CPPUNIT_ASSERT_EQUAL(600, test4.first.nanosecond());
149  CPPUNIT_ASSERT_EQUAL("2017-08-23T19:40:15.9850776+02:30"s, test4.first.toIsoString(test4.second));
150  // test negative delta
151  const auto test5 = DateTime::fromIsoString("2017-08-23T19:40:15.985077682-02:30");
152  CPPUNIT_ASSERT_EQUAL(-2.5, test5.second.totalHours());
153  CPPUNIT_ASSERT_EQUAL(15, test5.first.second());
154  CPPUNIT_ASSERT_EQUAL(985, test5.first.millisecond());
155  CPPUNIT_ASSERT_EQUAL(77, test5.first.microsecond());
156  CPPUNIT_ASSERT_EQUAL(600, test5.first.nanosecond());
157  CPPUNIT_ASSERT_EQUAL("2017-08-23T19:40:15.9850776-02:30"s, test5.first.toIsoString(test5.second));
158  // test further variants
159  CPPUNIT_ASSERT_EQUAL_MESSAGE("Zulu time", TimeSpan(), DateTime::fromIsoString("2017-08-23T19:40:15.985077682Z").second);
160  CPPUNIT_ASSERT_EQUAL_MESSAGE("no minutes", TimeSpan::fromHours(3), DateTime::fromIsoString("2017-08-23T19:40:15.985077682+03").second);
161  const auto test6 = DateTime::fromIsoString("1970-01-01T01:02:03+01:00");
162  CPPUNIT_ASSERT_EQUAL_MESSAGE("no seconds fraction", DateTime::fromDateAndTime(1970, 1, 1, 1, 2, 3), test6.first);
163  CPPUNIT_ASSERT_EQUAL_MESSAGE("no seconds fraction", TimeSpan::fromHours(1.0), test6.second);
164  // test invalid characters
165  CPPUNIT_ASSERT_THROW_MESSAGE("digits after Z", DateTime::fromIsoString("2017-O8-23T19:40:15.985077682Z02:00"), ConversionException);
166  CPPUNIT_ASSERT_THROW_MESSAGE("invalid letter", DateTime::fromIsoString("2017-O8-23T19:40:15.985077682:+02:00"), ConversionException);
167  CPPUNIT_ASSERT_THROW_MESSAGE("invalid T", DateTime::fromIsoString("2017-08-23T19:T40:15.985077682+02:00"), ConversionException);
168  CPPUNIT_ASSERT_THROW_MESSAGE("invalid -", DateTime::fromIsoString("2017-08-23T19:40-15.985077682+02:00"), ConversionException);
169  CPPUNIT_ASSERT_THROW_MESSAGE("invalid .", DateTime::fromIsoString("2017-08.5-23T19:40:15.985077682+02:00"), ConversionException);
170  CPPUNIT_ASSERT_THROW_MESSAGE("invalid :", DateTime::fromIsoString("2017:08-23T19:40:15.985077682+02:00"), ConversionException);
171  CPPUNIT_ASSERT_THROW_MESSAGE("invalid :", DateTime::fromIsoString("2017-08-23T19:40:15:985077682+02:00"), ConversionException);
172 
173 // test now() and exactNow() (or at least whether both behave the same)
174 #if defined(PLATFORM_UNIX)
175  const auto delta = DateTime::gmtNow() - DateTime::exactGmtNow();
176  CPPUNIT_ASSERT(delta < TimeSpan::fromSeconds(2) && delta > TimeSpan::fromSeconds(-2));
177 #endif
178 }
179 
184 {
185  // test fromString(...), this should also test all other from...() methods and + operator
186  CPPUNIT_ASSERT_EQUAL(TimeSpan(), TimeSpan::fromString(string()));
187  CPPUNIT_ASSERT_EQUAL(TimeSpan::fromSeconds(5.0), TimeSpan::fromString("5.0"));
188  CPPUNIT_ASSERT_EQUAL(TimeSpan::fromMinutes(5.5), TimeSpan::fromString("5:30"));
189  CPPUNIT_ASSERT_EQUAL(TimeSpan::fromHours(7) + TimeSpan::fromMinutes(5.5), TimeSpan::fromString("7:5:30"));
190  const auto test1 = TimeSpan::fromString("2:34:53:2.5");
191  // test days(), hours(), ...
192  CPPUNIT_ASSERT_EQUAL(3, test1.days());
193  CPPUNIT_ASSERT_EQUAL(10, test1.hours());
194  CPPUNIT_ASSERT_EQUAL(53, test1.minutes());
195  CPPUNIT_ASSERT_EQUAL(2, test1.seconds());
196  CPPUNIT_ASSERT_EQUAL(500, test1.milliseconds());
197  CPPUNIT_ASSERT(test1.totalDays() > 3.0 && test1.totalDays() < 4.0);
198  CPPUNIT_ASSERT(test1.totalHours() > (2 * 24 + 34) && test1.totalHours() < (2 * 24 + 35));
199  CPPUNIT_ASSERT(test1.totalMinutes() > (2 * 24 * 60 + 34 * 60 + 53) && test1.totalHours() < (2 * 24 * 60 + 34 * 60 + 54));
200  // test toString(...)
201  CPPUNIT_ASSERT_EQUAL("3 d 10 h 53 min 2 s 500 ms"s, test1.toString(TimeSpanOutputFormat::WithMeasures, false));
202  CPPUNIT_ASSERT_EQUAL("07:05:30"s, (TimeSpan::fromHours(7) + TimeSpan::fromMinutes(5.5)).toString());
203  CPPUNIT_ASSERT_EQUAL("-5 s"s, TimeSpan::fromSeconds(-5.0).toString(TimeSpanOutputFormat::WithMeasures, false));
204  CPPUNIT_ASSERT_EQUAL("0 s"s, TimeSpan().toString(TimeSpanOutputFormat::WithMeasures, false));
205  CPPUNIT_ASSERT_EQUAL("5e+02 µs"s, TimeSpan::fromMilliseconds(0.5).toString(TimeSpanOutputFormat::WithMeasures, false));
206  // test accuracy (of 100 nanoseconds)
207  const auto test2 = TimeSpan::fromString("15.985077682");
208  CPPUNIT_ASSERT_EQUAL(15.9850776, test2.totalSeconds());
209  CPPUNIT_ASSERT_EQUAL(15, test2.seconds());
210  CPPUNIT_ASSERT_EQUAL(985, test2.milliseconds());
211  CPPUNIT_ASSERT_EQUAL(77, test2.microseconds());
212  CPPUNIT_ASSERT_EQUAL(600, test2.nanoseconds());
213  CPPUNIT_ASSERT_EQUAL("00:00:15.9850776"s, test2.toString());
214  CPPUNIT_ASSERT_EQUAL("15 s 985 ms 77 µs 600 ns"s, test2.toString(TimeSpanOutputFormat::WithMeasures));
215  CPPUNIT_ASSERT_EQUAL("15.9850776"s, test2.toString(TimeSpanOutputFormat::TotalSeconds));
216 
217  // test whether ConversionException() is thrown when invalid values are specified
218  CPPUNIT_ASSERT_THROW(TimeSpan::fromString("2:34a:53:32.5"), ConversionException);
219 }
220 
225 {
226  auto dateTime = DateTime::fromDateAndTime(1999, 1, 5, 4, 16);
227  CPPUNIT_ASSERT_EQUAL(7, (dateTime + TimeSpan::fromDays(2)).day());
228  CPPUNIT_ASSERT_EQUAL(6, (dateTime + TimeSpan::fromHours(24)).day());
229  CPPUNIT_ASSERT_EQUAL(3, (dateTime + TimeSpan::fromHours(24) + TimeSpan::fromHours(-1)).hour());
230  CPPUNIT_ASSERT_EQUAL(17, (dateTime + TimeSpan::fromHours(24) - TimeSpan::fromMinutes(-1)).minute());
231  dateTime += TimeSpan::fromDays(365);
232  CPPUNIT_ASSERT_EQUAL(2000, dateTime.year());
233  CPPUNIT_ASSERT_EQUAL(5, dateTime.day());
234 }
235 
240 {
241  const auto begin(DateTime::fromDateAndTime(1994, 7, 18, 15, 30, 21)), end(DateTime::fromDateAndTime(2017, 12, 2, 15, 30, 21));
242  const Period period(begin, end);
243  CPPUNIT_ASSERT_EQUAL(23, period.years());
244  CPPUNIT_ASSERT_EQUAL(4, period.months());
245  CPPUNIT_ASSERT_EQUAL(14, period.days());
246  CPPUNIT_ASSERT_EQUAL(end.toString(), (begin + period).toString());
247 
248  const auto end2(DateTime::fromDateAndTime(2018, 1, 2, 15, 30, 21));
249  const Period period2(begin, end2);
250  CPPUNIT_ASSERT_EQUAL(23, period2.years());
251  CPPUNIT_ASSERT_EQUAL(5, period2.months());
252  CPPUNIT_ASSERT_EQUAL_MESSAGE("one more day, because December has 31 days", 15, period2.days());
253  CPPUNIT_ASSERT_EQUAL(end2.toString(), (begin + period2).toString());
254 }
255 
260 {
261  set<DateTime> dateTimes;
262  dateTimes.emplace(DateTime::fromDate(2500, 2, 1));
263  dateTimes.emplace(DateTime::fromDate(2500, 2, 2));
264  dateTimes.emplace(DateTime::fromDate(2500, 2, 1));
265  CPPUNIT_ASSERT_EQUAL(2_st, dateTimes.size());
266 
267  set<TimeSpan> timeSpans;
268  timeSpans.emplace(TimeSpan::fromDays(5));
269  timeSpans.emplace(TimeSpan::fromDays(10));
270  timeSpans.emplace(TimeSpan::fromDays(5));
271  CPPUNIT_ASSERT_EQUAL(2_st, timeSpans.size());
272 }
CPPUNIT_TEST_SUITE_REGISTRATION
CPPUNIT_TEST_SUITE_REGISTRATION(ChronoTests)
CppUtilities::Period
Represents a period of time.
Definition: period.h:8
ChronoTests::testDateTime
void testDateTime()
Tests most important DateTime features.
Definition: chronotests.cpp:96
CppUtilities::Period::days
constexpr int days() const
Returns the days component of the period represented by the current instance.
Definition: period.h:48
ChronoTests::testHashing
void testHashing()
Tests hashing DateTime / TimeSpan by using in a set.
Definition: chronotests.cpp:259
ChronoTests::setUp
void setUp()
Definition: chronotests.cpp:77
ChronoTests::testOperators
void testOperators()
Tests operators of DateTime / TimeSpan.
Definition: chronotests.cpp:224
CppUtilities::Period::months
constexpr int months() const
Returns the months component of the period represented by the current instance.
Definition: period.h:40
CppUtilities
Contains all utilities provides by the c++utilities library.
Definition: argumentparser.h:17
ChronoTests::testTimeSpan
void testTimeSpan()
Tests most important TimeSpan features.
Definition: chronotests.cpp:183
ChronoTests
The ChronoTests class tests classes and methods of the ChronoUtilities namespace.
Definition: chronotests.cpp:67
CppUtilities::ConversionException
Definition: conversionexception.h:11
CppUtilities::Period::years
constexpr int years() const
Returns the years component of the period represented by the current instance.
Definition: period.h:32
CppUtilities::TimeSpan
Represents a time interval.
Definition: timespan.h:25
CppUtilities::Literals
Contains literals to ease asserting with CPPUNIT_ASSERT_EQUAL.
Definition: testutils.h:298
CppUtilities::DateTime
Represents an instant in time, typically expressed as a date and time of day.
Definition: datetime.h:51
ChronoTests::tearDown
void tearDown()
Definition: chronotests.cpp:80
ChronoTests::testPeriod
void testPeriod()
Tests Period.
Definition: chronotests.cpp:239