jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/868173 )

Change subject: [Feature] Allow normalization of WbTime objects
......................................................................

[Feature] Allow normalization of WbTime objects

* Makes a new WbTime object that omits any parameters that
are not represented by the precision
* Handles precisions lower than "year"

Bug: T123888
Change-Id: Iabb820ad20e6b76f9aec8cacd6134f6e135e4a81
---
M pywikibot/__init__.py
M tests/wikibase_tests.py
2 files changed, 194 insertions(+), 0 deletions(-)

Approvals:
  Matěj Suchánek: Looks good to me, but someone else must approve
  Xqt: Looks good to me, approved
  jenkins-bot: Verified




diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py
index db7bdfe..f4e7889 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -486,6 +486,75 @@
                                timezone=timezone, calendarmodel=calendarmodel,
                                site=site)

+    def normalize(self) -> 'WbTime':
+        """Normalizes the WbTime object to account for precision.
+
+        Normalization is needed because WbTime objects can have hidden
+        values that affect naive comparisons, such as an object set to
+        a precision of YEAR but containing a month and day value.
+
+        This function returns a new normalized object and does not do
+        any modification in place.
+
+        Note: Normalized WbTime objects can only be compared to other
+        normalized WbTime objects of the same precision. Normalization
+        might make a WbTime object that was less than another WbTime object
+        before normalization, greater than it after normalization, or vice
+        versa.
+        """
+        year = self.year
+        # This is going to get messy.
+        if self.PRECISION['1000000000'] <= self.precision <= 
self.PRECISION['10000']:  # noqa: E501
+            # 1000000000 == 10^9
+            power_of_10 = 10 ** (9 - self.precision)
+            # Wikidata rounds the number based on the first non-decimal digit.
+            # Python's round function will round -15.5 to -16, and +15.5 to +16
+            # so we don't need to do anything complicated like the other
+            # examples.
+            year = round(year / power_of_10) * power_of_10
+        elif self.precision == self.PRECISION['millenia']:
+            # Similar situation with centuries
+            year_float = year / 1000
+            if year_float < 0:
+                year = math.floor(year_float)
+            else:
+                year = math.ceil(year_float)
+            year *= 1000
+        elif self.precision == self.PRECISION['century']:
+            # For century, -1301 is the same century as -1400 but not -1401.
+            # Similar for 1901 and 2000 vs 2001.
+            year_float = year / 100
+            if year_float < 0:
+                year = math.floor(year_float)
+            else:
+                year = math.ceil(year_float)
+            year *= 100
+        elif self.precision == self.PRECISION['decade']:
+            # For decade, -1340 is the same decade as -1349 but not -1350.
+            # Similar for 2010 and 2019 vs 2020
+            year_float = year / 10
+            year = math.trunc(year_float)
+            year *= 10
+        kwargs = {
+            'precision': self.precision,
+            'before': self.before,
+            'after': self.after,
+            'timezone': self.timezone,
+            'calendarmodel': self.calendarmodel,
+            'year': year
+        }
+        if self.precision >= self.PRECISION['month']:
+            kwargs['month'] = self.month
+        if self.precision >= self.PRECISION['day']:
+            kwargs['day'] = self.day
+        if self.precision >= self.PRECISION['hour']:
+            kwargs['hour'] = self.hour
+        if self.precision >= self.PRECISION['minute']:
+            kwargs['minute'] = self.minute
+        if self.precision >= self.PRECISION['second']:
+            kwargs['second'] = self.second
+        return type(self)(**kwargs)
+
     def toTimestr(self, force_iso: bool = False) -> str:
         """
         Convert the data to a UTC date/time string.
diff --git a/tests/wikibase_tests.py b/tests/wikibase_tests.py
index c97f6f7..3e7bfdb 100755
--- a/tests/wikibase_tests.py
+++ b/tests/wikibase_tests.py
@@ -343,6 +343,117 @@
                                               hour=0, minute=5, site=repo))
         self.assertEqual(t9.precision, pywikibot.WbTime.PRECISION['minute'])

+    def test_WbTime_normalization(self):
+        """Test WbTime normalization."""
+        repo = self.get_repo()
+        # flake8 is being annoying, so to reduce line length, I'll make
+        # some aliases here
+        decade = pywikibot.WbTime.PRECISION['decade']
+        century = pywikibot.WbTime.PRECISION['century']
+        millenia = pywikibot.WbTime.PRECISION['millenia']
+        t = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                             minute=43, second=12)
+        t2 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=pywikibot.WbTime.PRECISION['second'])
+        t3 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=pywikibot.WbTime.PRECISION['minute'])
+        t4 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=pywikibot.WbTime.PRECISION['hour'])
+        t5 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=pywikibot.WbTime.PRECISION['day'])
+        t6 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=pywikibot.WbTime.PRECISION['month'])
+        t7 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=pywikibot.WbTime.PRECISION['year'])
+        t8 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=decade)
+        t9 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                              minute=43, second=12,
+                              precision=century)
+        t10 = pywikibot.WbTime(site=repo, year=2010, month=1, day=1, hour=12,
+                               minute=43, second=12,
+                               precision=millenia)
+        self.assertEqual(t.normalize(), t)
+        self.assertEqual(t2.normalize(), t.normalize())
+        self.assertEqual(t3.normalize(),
+                         pywikibot.WbTime(site=repo, year=2010, month=1,
+                                          day=1, hour=12, minute=43))
+        self.assertEqual(t4.normalize(),
+                         pywikibot.WbTime(site=repo, year=2010,
+                                          month=1, day=1, hour=12))
+        self.assertEqual(t5.normalize(),
+                         pywikibot.WbTime(site=repo, year=2010,
+                                          month=1, day=1))
+        self.assertEqual(t6.normalize(),
+                         pywikibot.WbTime(site=repo, year=2010,
+                                          month=1))
+        self.assertEqual(
+            t7.normalize(), pywikibot.WbTime(site=repo, year=2010))
+        self.assertEqual(t8.normalize(),
+                         pywikibot.WbTime(site=repo, year=2010,
+                         precision=decade))
+        self.assertEqual(t9.normalize(),
+                         pywikibot.WbTime(site=repo, year=2100,
+                         precision=century))
+        self.assertEqual(t9.normalize(),
+                         pywikibot.WbTime(site=repo, year=2010,
+                                          precision=century).normalize())
+        self.assertEqual(t10.normalize(),
+                         pywikibot.WbTime(site=repo, year=3000,
+                                          precision=millenia))
+        self.assertEqual(t10.normalize(),
+                         pywikibot.WbTime(site=repo, year=2010,
+                                          precision=millenia).normalize())
+
+    def test_WbTime_normalization_very_low_precision(self):
+        """Test WbTime normalization with very low precision."""
+        repo = self.get_repo()
+        # flake8 is being annoying, so to reduce line length, I'll make
+        # some aliases here
+        year_10000 = pywikibot.WbTime.PRECISION['10000']
+        year_100000 = pywikibot.WbTime.PRECISION['100000']
+        year_1000000 = pywikibot.WbTime.PRECISION['1000000']
+        year_10000000 = pywikibot.WbTime.PRECISION['10000000']
+        year_100000000 = pywikibot.WbTime.PRECISION['100000000']
+        year_1000000000 = pywikibot.WbTime.PRECISION['1000000000']
+        t = pywikibot.WbTime(site=repo, year=-3124684989,
+                             precision=year_10000)
+        t2 = pywikibot.WbTime(site=repo, year=-3124684989,
+                              precision=year_100000)
+        t3 = pywikibot.WbTime(site=repo, year=-3124684989,
+                              precision=year_1000000)
+        t4 = pywikibot.WbTime(site=repo, year=-3124684989,
+                              precision=year_10000000)
+        t5 = pywikibot.WbTime(site=repo, year=-3124684989,
+                              precision=year_100000000)
+        t6 = pywikibot.WbTime(site=repo, year=-3124684989,
+                              precision=year_1000000000)
+        self.assertEqual(t.normalize(),
+                         pywikibot.WbTime(site=repo, year=-3124680000,
+                         precision=year_10000))
+        self.assertEqual(t2.normalize(),
+                         pywikibot.WbTime(site=repo, year=-3124700000,
+                                          precision=year_100000))
+        self.assertEqual(t3.normalize(),
+                         pywikibot.WbTime(site=repo, year=-3125000000,
+                                          precision=year_1000000))
+        self.assertEqual(t4.normalize(),
+                         pywikibot.WbTime(site=repo, year=-3120000000,
+                                          precision=year_10000000))
+        self.assertEqual(t5.normalize(),
+                         pywikibot.WbTime(site=repo, year=-3100000000,
+                                          precision=year_100000000))
+        self.assertEqual(t6.normalize(),
+                         pywikibot.WbTime(site=repo, year=-3000000000,
+                                          precision=year_1000000000))
+
     def test_WbTime_timestamp(self):
         """Test timestamp functions of WbTime."""
         repo = self.get_repo()

--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/868173
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Iabb820ad20e6b76f9aec8cacd6134f6e135e4a81
Gerrit-Change-Number: 868173
Gerrit-PatchSet: 5
Gerrit-Owner: RPI2026F1 <[email protected]>
Gerrit-Reviewer: JJMC89 <[email protected]>
Gerrit-Reviewer: Matěj Suchánek <[email protected]>
Gerrit-Reviewer: RPI2026F1 <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to