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()
pywikibot-commits@lists.wikimedia.org