Fixed TimePlugin timezone issue

The existing time plugin had a hard coded PDT for pacific timezone,
when it wasn't.   This patch adds some real timezone conversion from
utc to the tz of the running aprsd server.   This will eventually allow
us to use either the tz of the running aprsd and/or the tz of the
calling callsign if we can just get the tz string from the location
beacon of the caller's callsign.
This commit is contained in:
Hemna 2021-01-19 11:19:53 -05:00
parent ca05676c98
commit 9f38fd179e
5 changed files with 51 additions and 20 deletions

View File

@ -2,6 +2,7 @@ import logging
import time import time
from aprsd import fuzzyclock, plugin from aprsd import fuzzyclock, plugin
import pytz
LOG = logging.getLogger("APRSD") LOG = logging.getLogger("APRSD")
@ -13,16 +14,34 @@ class TimePlugin(plugin.APRSDPluginBase):
command_regex = "^[tT]" command_regex = "^[tT]"
command_name = "time" 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): def command(self, fromcall, message, ack):
LOG.info("TIME COMMAND") LOG.info("TIME COMMAND")
stm = time.localtime() # So we can mock this in unit tests
h = stm.tm_hour localzone = self._get_local_tz()
m = stm.tm_min
cur_time = fuzzyclock.fuzzy(h, m, 1) # This is inefficient for now, but this enables
reply = "{} ({}:{} PDT) ({})".format( # 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, cur_time,
str(h), local_short_str,
str(m).rjust(2, "0"),
message.rstrip(), message.rstrip(),
) )
return reply return reply

View File

@ -160,7 +160,7 @@ typing-extensions==3.7.4.3
# mypy # mypy
urllib3==1.26.2 urllib3==1.26.2
# via requests # via requests
virtualenv==20.2.2 virtualenv==20.4.0
# via tox # via tox
webencodings==0.5.1 webencodings==0.5.1
# via bleach # via bleach

View File

@ -10,3 +10,4 @@ thesmuggler
aprslib aprslib
py3-validate-email py3-validate-email
pre-commit pre-commit
pytz

View File

@ -28,13 +28,13 @@ filelock==3.0.12
# via # via
# py3-validate-email # py3-validate-email
# virtualenv # virtualenv
identify==1.5.11 identify==1.5.13
# via pre-commit # via pre-commit
idna==2.10 idna==2.10
# via # via
# py3-validate-email # py3-validate-email
# requests # requests
imapclient==2.1.0 imapclient==2.2.0
# via -r requirements.in # via -r requirements.in
jinja2==2.11.2 jinja2==2.11.2
# via click-completion # via click-completion
@ -50,6 +50,8 @@ pre-commit==2.9.3
# via -r requirements.in # via -r requirements.in
py3-validate-email==0.2.12 py3-validate-email==0.2.12
# via -r requirements.in # via -r requirements.in
pytz==2020.5
# via -r requirements.in
pyyaml==5.3.1 pyyaml==5.3.1
# via # via
# -r requirements.in # -r requirements.in
@ -70,5 +72,5 @@ toml==0.10.2
# via pre-commit # via pre-commit
urllib3==1.26.2 urllib3==1.26.2
# via requests # via requests
virtualenv==20.2.2 virtualenv==20.4.0
# via pre-commit # via pre-commit

View File

@ -9,6 +9,7 @@ from aprsd.plugins import ping as ping_plugin
from aprsd.plugins import query as query_plugin from aprsd.plugins import query as query_plugin
from aprsd.plugins import time as time_plugin from aprsd.plugins import time as time_plugin
from aprsd.plugins import version as version_plugin from aprsd.plugins import version as version_plugin
import pytz
class TestPlugin(unittest.TestCase): class TestPlugin(unittest.TestCase):
@ -68,13 +69,21 @@ class TestPlugin(unittest.TestCase):
actual = query.run(self.fromcall, message, self.ack) actual = query.run(self.fromcall, message, self.ack)
mock_restart.assert_called_once() mock_restart.assert_called_once()
@mock.patch("time.localtime") @mock.patch("aprsd.plugins.time.TimePlugin._get_local_tz")
def test_time(self, mock_time): @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() fake_time = mock.MagicMock()
h = fake_time.tm_hour = 16 h = int(local_t.strftime("%H"))
m = fake_time.tm_min = 12 m = int(local_t.strftime("%M"))
fake_time.tm_sec = 55 fake_time.tm_sec = 13
mock_time.return_value = fake_time
time = time_plugin.TimePlugin(self.config) time = time_plugin.TimePlugin(self.config)
fromcall = "KFART" fromcall = "KFART"
@ -87,10 +96,10 @@ class TestPlugin(unittest.TestCase):
cur_time = fuzzy(h, m, 1) cur_time = fuzzy(h, m, 1)
message = "time" message = "time"
expected = "{} ({}:{} PDT) ({})".format( local_short_str = local_t.strftime("%H:%M %Z")
expected = "{} ({}) ({})".format(
cur_time, cur_time,
str(h), local_short_str,
str(m).rjust(2, "0"),
message.rstrip(), message.rstrip(),
) )
actual = time.run(fromcall, message, ack) actual = time.run(fromcall, message, ack)