Improve period compution
This commit is contained in:
parent
a89f6f9ce4
commit
26cd303422
|
@ -35,14 +35,15 @@ namespace ChronoUtilities {
|
|||
*/
|
||||
Period::Period(const DateTime &begin, const DateTime &end)
|
||||
{
|
||||
m_years = end.year() - beg.year();
|
||||
m_months = end.month() - beg.month();
|
||||
m_days = end.day() - beg.day();
|
||||
if (end.hour() < beg.hour()) {
|
||||
--m_days;
|
||||
m_years = end.year() - begin.year();
|
||||
m_months = end.month() - begin.month();
|
||||
if (m_months < 0) {
|
||||
m_months += 12;
|
||||
--m_years;
|
||||
}
|
||||
m_days = end.day() - begin.day();
|
||||
if (m_days < 0) {
|
||||
m_days += DateTime::daysInMonth(beg.year(), beg.month());
|
||||
m_days += end.month() > 1 ? DateTime::daysInMonth(end.year(), end.month() - 1) : 31;
|
||||
--m_months;
|
||||
}
|
||||
if (m_months < 0) {
|
||||
|
@ -50,4 +51,33 @@ Period::Period(const DateTime &begin, const DateTime &end)
|
|||
--m_years;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds the specified \a period to the specified date.
|
||||
* \throws Might throw ConversionException if resulting DateTime would be out-of-range.
|
||||
* \remarks
|
||||
* - The order in which the years(), month() and days() are added matters. See the overall class description.
|
||||
* - Since the accuracy of Period is only one day, the DateTime::timeOfDay() of the result always equals begin.timeOfDay().
|
||||
*/
|
||||
DateTime operator+(DateTime begin, Period period)
|
||||
{
|
||||
auto year = begin.year() + period.years();
|
||||
auto month = begin.month() + period.months();
|
||||
if (month > 12) {
|
||||
month -= 12;
|
||||
++year;
|
||||
}
|
||||
auto day = begin.day() + period.days();
|
||||
const auto maxDays = DateTime::daysInMonth(year, month);
|
||||
if (day > maxDays) {
|
||||
day -= maxDays;
|
||||
++month;
|
||||
}
|
||||
if (month > 12) {
|
||||
month -= 12;
|
||||
++year;
|
||||
}
|
||||
return DateTime::fromDate(year, month, day) + begin.timeOfDay();
|
||||
}
|
||||
|
||||
} // namespace ChronoUtilities
|
||||
|
|
|
@ -41,6 +41,9 @@ inline int Period::days() const
|
|||
{
|
||||
return m_days;
|
||||
}
|
||||
|
||||
DateTime operator+(DateTime begin, Period period);
|
||||
|
||||
} // namespace ChronoUtilities
|
||||
|
||||
#endif // CHRONO_UTILITIES_PERIOD_H
|
||||
|
|
|
@ -29,6 +29,7 @@ class ChronoTests : public TestFixture {
|
|||
CPPUNIT_TEST(testDateTime);
|
||||
CPPUNIT_TEST(testTimeSpan);
|
||||
CPPUNIT_TEST(testOperators);
|
||||
CPPUNIT_TEST(testPeriod);
|
||||
CPPUNIT_TEST(testHashing);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
|
@ -43,6 +44,7 @@ public:
|
|||
void testDateTime();
|
||||
void testTimeSpan();
|
||||
void testOperators();
|
||||
void testPeriod();
|
||||
void testHashing();
|
||||
};
|
||||
|
||||
|
@ -159,7 +161,26 @@ void ChronoTests::testOperators()
|
|||
dateTime += TimeSpan::fromDays(365);
|
||||
CPPUNIT_ASSERT_EQUAL(2000, dateTime.year());
|
||||
CPPUNIT_ASSERT_EQUAL(5, dateTime.day());
|
||||
CPPUNIT_ASSERT_EQUAL(2, Period(dateTime, dateTime + TimeSpan::fromDays(62)).months());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Tests Period.
|
||||
*/
|
||||
void ChronoTests::testPeriod()
|
||||
{
|
||||
const auto begin(DateTime::fromDateAndTime(1994, 7, 18, 15, 30, 21)), end(DateTime::fromDateAndTime(2017, 12, 2, 15, 30, 21));
|
||||
const Period period(begin, end);
|
||||
CPPUNIT_ASSERT_EQUAL(23, period.years());
|
||||
CPPUNIT_ASSERT_EQUAL(4, period.months());
|
||||
CPPUNIT_ASSERT_EQUAL(14, period.days());
|
||||
CPPUNIT_ASSERT_EQUAL(end.toString(), (begin + period).toString());
|
||||
|
||||
const auto end2(DateTime::fromDateAndTime(2018, 1, 2, 15, 30, 21));
|
||||
const Period period2(begin, end2);
|
||||
CPPUNIT_ASSERT_EQUAL(23, period2.years());
|
||||
CPPUNIT_ASSERT_EQUAL(5, period2.months());
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("one more day, because December has 31 days", 15, period2.days());
|
||||
CPPUNIT_ASSERT_EQUAL(end2.toString(), (begin + period2).toString());
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
Loading…
Reference in New Issue