jenkins-bot has submitted this change and it was merged.
Change subject: [FEAT] Date: Add/subtract months from a date
......................................................................
[FEAT] Date: Add/subtract months from a date
This allows to add or subtract any number of months with a calendar that
has 12 months. It can also calculate the difference between two days in
terms of months.
Because Python's datetime module is based around a calendar with 12
months it works directly on it and assumes that a year has always 12
months.
Bug: T73124
Change-Id: I4b204465b7224f4d86e3f4462847002f3382ac3a
---
M pywikibot/date.py
M tests/date_tests.py
2 files changed, 78 insertions(+), 1 deletion(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/date.py b/pywikibot/date.py
index 350bdf7..7181ba8 100644
--- a/pywikibot/date.py
+++ b/pywikibot/date.py
@@ -14,6 +14,8 @@
__version__ = '$Id$'
#
+import calendar
+import datetime
import re
import sys
@@ -2343,5 +2345,52 @@
return formats['YearAD'][lang](year)
+def apply_month_delta(date, month_delta=1, add_overlap=False):
+ """
+ Add or subtract months from the date.
+
+ By default if the new month has less days then the day of the date it
+ chooses the last day in the new month. For example a date in the March 31st
+ added by one month will result in April 30th.
+
+ When the overlap is enabled, and there is overlap, then the new_date will be
+ one month off and get_month_delta will report a number one higher.
+
+ It does only work on calendars with 12 months per year, and where the months
+ are numbered consecutively beginning by 1.
+
+ @param date: The starting date
+ @type date: date
+ @param month_delta: The amount of months added or subtracted.
+ @type month_delta: int
+ @param add_overlap: Add any missing days to the date, increasing the month
+ once more.
+ @type add_overlap: bool
+ @return: The end date
+ @rtype: type of date
+ """
+ if int(month_delta) != month_delta:
+ raise ValueError('Month delta must be an integer')
+ month = (date.month - 1) + month_delta
+ year = date.year + month // 12
+ month = month % 12 + 1
+ day = min(date.day, calendar.monthrange(year, month)[1])
+ new_date = date.replace(year, month, day)
+ if add_overlap and day != date.day:
+ assert(date.day > day)
+ new_date += datetime.timedelta(days=date.day - day)
+ return new_date
+
+
+def get_month_delta(date1, date2):
+ """
+ Return the difference between to dates in months.
+
+ It does only work on calendars with 12 months per year, and where the months
+ are consecutive and non-negative numbers.
+ """
+ return date2.month - date1.month + (date2.year - date1.year) * 12
+
+
if __name__ == "__main__":
print(__doc__)
diff --git a/tests/date_tests.py b/tests/date_tests.py
index 8c236f3..c7058ed 100644
--- a/tests/date_tests.py
+++ b/tests/date_tests.py
@@ -5,7 +5,7 @@
#
# Distributed under the terms of the MIT license.
#
-__version__ = '$Id$'
+from datetime import datetime
from pywikibot import date
from tests.aspects import unittest, MetaTestCaseClass, TestCase
@@ -60,6 +60,34 @@
net = False
+class TestMonthDelta(TestCase):
+
+ """Tests for adding months to a date and getting the months between
two."""
+
+ net = False
+
+ def test_apply_positive_delta(self):
+ """Test adding months to a date."""
+ self.assertEqual(datetime(2012, 3, 10), date.apply_month_delta(datetime(2012, 1,
10), 2))
+ self.assertEqual(datetime(2012, 3, 31), date.apply_month_delta(datetime(2012, 1,
31), 2))
+ self.assertEqual(datetime(2012, 2, 29), date.apply_month_delta(datetime(2012, 1,
31)))
+ self.assertEqual(datetime(2012, 3, 2), date.apply_month_delta(datetime(2012, 1,
31), add_overlap=True))
+
+ def test_apply_negative_delta(self):
+ """Test adding months to a date."""
+ self.assertEqual(datetime(2012, 1, 10), date.apply_month_delta(datetime(2012, 3,
10), -2))
+ self.assertEqual(datetime(2012, 1, 31), date.apply_month_delta(datetime(2012, 3,
31), -2))
+ self.assertEqual(datetime(2012, 2, 29), date.apply_month_delta(datetime(2012, 3,
31), -1))
+ self.assertEqual(datetime(2012, 3, 2), date.apply_month_delta(datetime(2012, 3,
31), -1, add_overlap=True))
+
+ def test_get_delta(self):
+ """Test that the delta is calculated correctly."""
+ self.assertEqual(date.get_month_delta(datetime(2012, 1, 31), datetime(2012, 3,
31)), 2)
+ self.assertEqual(date.get_month_delta(datetime(2012, 3, 31), datetime(2012, 1,
31)), -2)
+ self.assertEqual(date.get_month_delta(datetime(2012, 3, 31), datetime(2013, 1,
31)), 10)
+ self.assertEqual(date.get_month_delta(datetime(2014, 3, 31), datetime(2013, 3,
31)), -12)
+
+
if __name__ == '__main__':
try:
unittest.main()
--
To view, visit
https://gerrit.wikimedia.org/r/176349
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I4b204465b7224f4d86e3f4462847002f3382ac3a
Gerrit-PatchSet: 2
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot <>