From: Michael Friedrich <michael.friedrich@icinga.com>
Date: Tue, 9 Jul 2019 14:13:54 +0000 (+0200)
Subject: Fix parsing of "day -X (last day of month)" in TimePeriod class
X-Git-Tag: v2.11.0-rc1~35^2~1
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0dc87668d62b00a61537b53baf91e28c7254e53d;p=icinga2

Fix parsing of "day -X (last day of month)" in TimePeriod class
---

diff --git a/lib/icinga/legacytimeperiod.cpp b/lib/icinga/legacytimeperiod.cpp
index 1275ae351..039fedc78 100644
--- a/lib/icinga/legacytimeperiod.cpp
+++ b/lib/icinga/legacytimeperiod.cpp
@@ -113,6 +113,13 @@ int LegacyTimePeriod::MonthFromString(const String& monthdef)
 		return -1;
 }
 
+boost::gregorian::date LegacyTimePeriod::GetEndOfMonthDay(int year, int month)
+{
+	boost::gregorian::date d(boost::gregorian::greg_year(year), boost::gregorian::greg_month(month), 1);
+
+	return d.end_of_month();
+}
+
 void LegacyTimePeriod::ParseTimeSpec(const String& timespec, tm *begin, tm *end, tm *reference)
 {
 	/* Let mktime() figure out whether we're in DST or not. */
@@ -170,10 +177,14 @@ void LegacyTimePeriod::ParseTimeSpec(const String& timespec, tm *begin, tm *end,
 			begin->tm_min = 0;
 			begin->tm_sec = 0;
 
-			/* day -1: Negative days are relative to the next month. */
+			/* day -X: Negative days are relative to the next month. */
 			if (mday < 0) {
-				begin->tm_mday = mday * -1 - 1;
-				begin->tm_mon++;
+				boost::gregorian::date d(GetEndOfMonthDay(reference->tm_year + 1900, mon + 1)); //TODO: Refactor this mess into full Boost.DateTime
+
+				*begin = boost::gregorian::to_tm(d);
+				begin->tm_hour = 0;
+				begin->tm_min = 0;
+				begin->tm_sec = 0;
 			}
 		}
 
@@ -185,10 +196,17 @@ void LegacyTimePeriod::ParseTimeSpec(const String& timespec, tm *begin, tm *end,
 			end->tm_min = 0;
 			end->tm_sec = 0;
 
-			/* day -1: Negative days are relative to the next month. */
+			/* day -X: Negative days are relative to the next month. */
 			if (mday < 0) {
-				end->tm_mday = mday * -1 - 1;
-				end->tm_mon++;
+				boost::gregorian::date d(GetEndOfMonthDay(reference->tm_year + 1900, mon + 1)); //TODO: Refactor this mess into full Boost.DateTime
+
+				// End date is one day in the future, starting 00:00:00
+				d = d + boost::gregorian::days(1);
+
+				*end = boost::gregorian::to_tm(d);
+				end->tm_hour = 0;
+				end->tm_min = 0;
+				end->tm_sec = 0;
 			}
 		}
 
diff --git a/lib/icinga/legacytimeperiod.hpp b/lib/icinga/legacytimeperiod.hpp
index 2b9767b2f..3f1a5cdb9 100644
--- a/lib/icinga/legacytimeperiod.hpp
+++ b/lib/icinga/legacytimeperiod.hpp
@@ -6,6 +6,7 @@
 #include "icinga/i2-icinga.hpp"
 #include "icinga/timeperiod.hpp"
 #include "base/dictionary.hpp"
+#include <boost/date_time/gregorian/gregorian.hpp>
 
 namespace icinga
 {
@@ -35,6 +36,8 @@ public:
 
 private:
 	LegacyTimePeriod();
+
+	static boost::gregorian::date GetEndOfMonthDay(int year, int month);
 };
 
 }