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)
|
Period::Period(const DateTime &begin, const DateTime &end)
|
||||||
{
|
{
|
||||||
m_years = end.year() - beg.year();
|
m_years = end.year() - begin.year();
|
||||||
m_months = end.month() - beg.month();
|
m_months = end.month() - begin.month();
|
||||||
m_days = end.day() - beg.day();
|
if (m_months < 0) {
|
||||||
if (end.hour() < beg.hour()) {
|
m_months += 12;
|
||||||
--m_days;
|
--m_years;
|
||||||
}
|
}
|
||||||
|
m_days = end.day() - begin.day();
|
||||||
if (m_days < 0) {
|
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;
|
--m_months;
|
||||||
}
|
}
|
||||||
if (m_months < 0) {
|
if (m_months < 0) {
|
||||||
|
@ -50,4 +51,33 @@ Period::Period(const DateTime &begin, const DateTime &end)
|
||||||
--m_years;
|
--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
|
} // namespace ChronoUtilities
|
||||||
|
|
|
@ -41,6 +41,9 @@ inline int Period::days() const
|
||||||
{
|
{
|
||||||
return m_days;
|
return m_days;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DateTime operator+(DateTime begin, Period period);
|
||||||
|
|
||||||
} // namespace ChronoUtilities
|
} // namespace ChronoUtilities
|
||||||
|
|
||||||
#endif // CHRONO_UTILITIES_PERIOD_H
|
#endif // CHRONO_UTILITIES_PERIOD_H
|
||||||
|
|
|
@ -29,6 +29,7 @@ class ChronoTests : public TestFixture {
|
||||||
CPPUNIT_TEST(testDateTime);
|
CPPUNIT_TEST(testDateTime);
|
||||||
CPPUNIT_TEST(testTimeSpan);
|
CPPUNIT_TEST(testTimeSpan);
|
||||||
CPPUNIT_TEST(testOperators);
|
CPPUNIT_TEST(testOperators);
|
||||||
|
CPPUNIT_TEST(testPeriod);
|
||||||
CPPUNIT_TEST(testHashing);
|
CPPUNIT_TEST(testHashing);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ public:
|
||||||
void testDateTime();
|
void testDateTime();
|
||||||
void testTimeSpan();
|
void testTimeSpan();
|
||||||
void testOperators();
|
void testOperators();
|
||||||
|
void testPeriod();
|
||||||
void testHashing();
|
void testHashing();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -159,7 +161,26 @@ void ChronoTests::testOperators()
|
||||||
dateTime += TimeSpan::fromDays(365);
|
dateTime += TimeSpan::fromDays(365);
|
||||||
CPPUNIT_ASSERT_EQUAL(2000, dateTime.year());
|
CPPUNIT_ASSERT_EQUAL(2000, dateTime.year());
|
||||||
CPPUNIT_ASSERT_EQUAL(5, dateTime.day());
|
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