Geograpy: Fix formatting of negative non-integral offsets (and improve others)

This commit is contained in:
Valentin Lorentz 2022-04-04 22:06:19 +02:00
parent 088d0f54dd
commit 4f3d6fc39f
2 changed files with 73 additions and 19 deletions

View File

@ -110,6 +110,21 @@ class Geography(callbacks.Plugin):
_("Could not find the timezone of this location."), Raise=True _("Could not find the timezone of this location."), Raise=True
) )
def _format_utc_offset(self, offset_seconds):
sign = "+" if offset_seconds >= 0 else "-"
# Make modulos work as expected
offset_seconds = abs(offset_seconds)
(offset_minutes, offset_seconds) = divmod(offset_seconds, 60)
(offset_hours, offset_minutes) = divmod(offset_minutes, 60)
offset = f"{offset_hours}:{offset_minutes:02}:{offset_seconds:02}"
# hide seconds and minutes if they are zero
offset = re.sub("(:00)+$", "", offset)
return f"UTC{sign}{offset}"
@wrap(["text"]) @wrap(["text"])
def timezone(self, irc, msg, args, query): def timezone(self, irc, msg, args, query):
"""<location name to search> """<location name to search>
@ -134,33 +149,28 @@ class Geography(callbacks.Plugin):
if timezone is None: if timezone is None:
continue continue
offset = str(datetime.datetime.now(tz=timezone).utcoffset()) offset_seconds = int(
if not offset.startswith("-"): datetime.datetime.now(tz=timezone).utcoffset().total_seconds())
offset = "+" + offset offset = self._format_utc_offset(offset_seconds)
# hide seconds and minutes if they are zero
offset = re.sub("(:00)+$", "", offset)
# Extract a human-friendly name, depending on the type of # Extract a human-friendly name, depending on the type of
# the timezone object: # the timezone object:
if hasattr(timezone, "key"): if hasattr(timezone, "key"):
# instance of zoneinfo.ZoneInfo # instance of zoneinfo.ZoneInfo
irc.reply(format("%s (currently UTC%s)", timezone.key, offset)) irc.reply(format("%s (currently %s)", timezone.key, offset))
return return
elif hasattr(timezone, "zone"): elif hasattr(timezone, "zone"):
# instance of pytz.timezone # instance of pytz.timezone
irc.reply(format("%s (currently UTC%s)", timezone.zone, offset)) irc.reply(format("%s (currently %s)", timezone.zone, offset))
return return
else: else:
# probably datetime.timezone built from a constant offset # probably datetime.timezone built from a constant offset
try: try:
offset = timezone.utcoffset(now).seconds offset = int(timezone.utcoffset(now).total_seconds())
except NotImplementedError: except NotImplementedError:
continue continue
hours = int(offset / 3600) irc.reply(self._format_utc_offset(offset))
minutes = int(offset / 60 % 60)
irc.reply("UTC+%0.2i:%0.2i" % (hours, minutes))
return return
irc.error( irc.error(

View File

@ -68,41 +68,85 @@ class GeographyTimezoneTestCase(PluginTestCase):
@mock @mock
def testTimezonePytz(self): def testTimezonePytz(self):
tz = pytz.timezone("Europe/Paris") tz = pytz.timezone("Europe/Paris")
with patch.object(wikidata, "timezone_from_uri", return_value=tz): with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp( self.assertRegexp(
"timezone Foo Bar", r"Europe/Paris \(currently UTC\+[12]\)" "timezone Foo Bar", r"Europe/Paris \(currently UTC\+[12]\)"
) )
tz = pytz.timezone("America/New_York")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone New York", r"America/New_York \(currently UTC-[45]\)"
)
tz = pytz.timezone("Canada/Newfoundland")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Newfoundland",
r"Canada/Newfoundland \(currently UTC-[23]:30\)"
)
tz = pytz.timezone("Asia/Kolkata")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Delhi", r"Asia/Kolkata \(currently UTC\+5:30\)"
)
@skipIf(not zoneinfo, "Python is older than 3.9") @skipIf(not zoneinfo, "Python is older than 3.9")
@mock @mock
def testTimezoneZoneinfo(self): def testTimezoneZoneinfo(self):
tz = zoneinfo.ZoneInfo("Europe/Paris") tz = zoneinfo.ZoneInfo("Europe/Paris")
with patch.object(wikidata, "timezone_from_uri", return_value=tz): with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp( self.assertRegexp(
"timezone Foo Bar", r"Europe/Paris \(currently UTC\+[12]\)" "timezone Foo Bar", r"Europe/Paris \(currently UTC\+[12]\)"
) )
tz = zoneinfo.ZoneInfo("America/New_York")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone New York", r"America/New_York \(currently UTC-[45]\)"
)
tz = zoneinfo.ZoneInfo("Canada/Newfoundland")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Newfoundland",
r"Canada/Newfoundland \(currently UTC-[23]:30\)"
)
tz = zoneinfo.ZoneInfo("Asia/Kolkata")
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertRegexp(
"timezone Delhi", r"Asia/Kolkata \(currently UTC\+5:30\)"
)
@skipIf(not zoneinfo, "Python is older than 3.9") @skipIf(not zoneinfo, "Python is older than 3.9")
@mock @mock
def testTimezoneAbsolute(self): def testTimezoneAbsolute(self):
tz = datetime.timezone(datetime.timedelta(hours=4)) tz = datetime.timezone(datetime.timedelta(hours=4))
with patch.object(wikidata, "timezone_from_uri", return_value=tz): with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertResponse("timezone Foo Bar", "UTC+04:00") self.assertResponse("timezone Foo Bar", "UTC+4")
tz = datetime.timezone(datetime.timedelta(hours=4, minutes=30)) tz = datetime.timezone(datetime.timedelta(hours=4, minutes=30))
with patch.object(wikidata, "timezone_from_uri", return_value=tz): with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertResponse("timezone Foo Bar", "UTC+04:30") self.assertResponse("timezone Foo Bar", "UTC+4:30")
tz = datetime.timezone(datetime.timedelta(hours=-4, minutes=30))
with patch.object(wikidata, "timezone_from_uri", return_value=tz):
self.assertResponse("timezone Foo Bar", "UTC-3:30")
@skipIf(not network, "Network test") @skipIf(not network, "Network test")
def testTimezoneIntegration(self): def testTimezoneIntegration(self):
self.assertRegexp( self.assertRegexp(
"timezone Metz, France", r"Europe/Paris \(currently UTC\+[12]\)" "timezone Metz, France", r"Europe/Paris \(currently UTC\+[12]\)"
) )
self.assertResponse("timezone Saint-Denis, La Réunion", "UTC+04:00") self.assertResponse("timezone Saint-Denis, La Réunion", "UTC+4")
self.assertRegexp(
"timezone Delhi", r"Asia/Kolkata \(currently UTC\+5:30\)"
)
self.assertRegexp(
"timezone Newfoundland", r"UTC-[23]:30"
)
class GeographyLocaltimeTestCase(PluginTestCase): class GeographyLocaltimeTestCase(PluginTestCase):