diff --git a/aprsd/plugins/time.py b/aprsd/plugins/time.py index 3c0c3b9..4510ec3 100644 --- a/aprsd/plugins/time.py +++ b/aprsd/plugins/time.py @@ -2,6 +2,7 @@ import logging import time from aprsd import fuzzyclock, plugin +import pytz LOG = logging.getLogger("APRSD") @@ -13,16 +14,34 @@ class TimePlugin(plugin.APRSDPluginBase): command_regex = "^[tT]" command_name = "time" + def _get_local_tz(self): + return pytz.timezone(time.strftime("%Z")) + + def _get_utcnow(self): + return pytz.datetime.datetime.utcnow() + def command(self, fromcall, message, ack): LOG.info("TIME COMMAND") - stm = time.localtime() - h = stm.tm_hour - m = stm.tm_min - cur_time = fuzzyclock.fuzzy(h, m, 1) - reply = "{} ({}:{} PDT) ({})".format( + # So we can mock this in unit tests + localzone = self._get_local_tz() + + # This is inefficient for now, but this enables + # us to add the ability to provide time in the TZ + # of the caller, if we can get the TZ from their callsign location + # This also accounts for running aprsd in different timezones + utcnow = self._get_utcnow() + gmt_t = pytz.utc.localize(utcnow) + local_t = gmt_t.astimezone(localzone) + + local_short_str = local_t.strftime("%H:%M %Z") + local_hour = local_t.strftime("%H") + local_min = local_t.strftime("%M") + cur_time = fuzzyclock.fuzzy(int(local_hour), int(local_min), 1) + + reply = "{} ({}) ({})".format( cur_time, - str(h), - str(m).rjust(2, "0"), + local_short_str, message.rstrip(), ) + return reply diff --git a/dev-requirements.txt b/dev-requirements.txt index 57100ae..2d5082c 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -160,7 +160,7 @@ typing-extensions==3.7.4.3 # mypy urllib3==1.26.2 # via requests -virtualenv==20.2.2 +virtualenv==20.4.0 # via tox webencodings==0.5.1 # via bleach diff --git a/requirements.in b/requirements.in index e81f136..c023737 100644 --- a/requirements.in +++ b/requirements.in @@ -10,3 +10,4 @@ thesmuggler aprslib py3-validate-email pre-commit +pytz diff --git a/requirements.txt b/requirements.txt index ed86b36..5eba174 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,13 +28,13 @@ filelock==3.0.12 # via # py3-validate-email # virtualenv -identify==1.5.11 +identify==1.5.13 # via pre-commit idna==2.10 # via # py3-validate-email # requests -imapclient==2.1.0 +imapclient==2.2.0 # via -r requirements.in jinja2==2.11.2 # via click-completion @@ -50,6 +50,8 @@ pre-commit==2.9.3 # via -r requirements.in py3-validate-email==0.2.12 # via -r requirements.in +pytz==2020.5 + # via -r requirements.in pyyaml==5.3.1 # via # -r requirements.in @@ -70,5 +72,5 @@ toml==0.10.2 # via pre-commit urllib3==1.26.2 # via requests -virtualenv==20.2.2 +virtualenv==20.4.0 # via pre-commit diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 83d9662..fecd16f 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -9,6 +9,7 @@ from aprsd.plugins import ping as ping_plugin from aprsd.plugins import query as query_plugin from aprsd.plugins import time as time_plugin from aprsd.plugins import version as version_plugin +import pytz class TestPlugin(unittest.TestCase): @@ -68,13 +69,21 @@ class TestPlugin(unittest.TestCase): actual = query.run(self.fromcall, message, self.ack) mock_restart.assert_called_once() - @mock.patch("time.localtime") - def test_time(self, mock_time): + @mock.patch("aprsd.plugins.time.TimePlugin._get_local_tz") + @mock.patch("aprsd.plugins.time.TimePlugin._get_utcnow") + def test_time(self, mock_utcnow, mock_localtz): + utcnow = pytz.datetime.datetime.utcnow() + mock_utcnow.return_value = utcnow + tz = pytz.timezone("US/Pacific") + mock_localtz.return_value = tz + + gmt_t = pytz.utc.localize(utcnow) + local_t = gmt_t.astimezone(tz) + fake_time = mock.MagicMock() - h = fake_time.tm_hour = 16 - m = fake_time.tm_min = 12 - fake_time.tm_sec = 55 - mock_time.return_value = fake_time + h = int(local_t.strftime("%H")) + m = int(local_t.strftime("%M")) + fake_time.tm_sec = 13 time = time_plugin.TimePlugin(self.config) fromcall = "KFART" @@ -87,10 +96,10 @@ class TestPlugin(unittest.TestCase): cur_time = fuzzy(h, m, 1) message = "time" - expected = "{} ({}:{} PDT) ({})".format( + local_short_str = local_t.strftime("%H:%M %Z") + expected = "{} ({}) ({})".format( cur_time, - str(h), - str(m).rjust(2, "0"), + local_short_str, message.rstrip(), ) actual = time.run(fromcall, message, ack)