diff --git a/setup.py b/setup.py index 89a3ad0..4349a8e 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages setup(name='simpleais', - version='0.6.4', + version='0.6.5', description='a simple ais parser', url='https://github.com/wpietri/simpleais', author='William Pietri', diff --git a/simpleais/tools.py b/simpleais/tools.py index ec27a95..c0764f5 100755 --- a/simpleais/tools.py +++ b/simpleais/tools.py @@ -12,6 +12,7 @@ import click import numpy +from dateutil.parser import parse as dateutil_parse from simpleais import sentences_from_source @@ -71,7 +72,7 @@ class Taster(object): pass def __init__(self, mmsi=None, sentence_type=None, vessel_class=None, lon=None, lat=None, field=None, value=None, - mode='and', checksum=None, invert_match=False): + before=None, after=None, mode='and', checksum=None, invert_match=False): self.mmsi = mmsi self.sentence_type = sentence_type self.vessel_class = vessel_class @@ -79,6 +80,8 @@ def __init__(self, mmsi=None, sentence_type=None, vessel_class=None, lon=None, l self.lat = lat self.field = field self.value = value + self.before = before + self.after = after if mode == 'and' or mode is None: self.default_result = [True] self.reducer = lambda x, y: x and y @@ -113,6 +116,10 @@ def likes(self, sentence): if self.value: for f, v in self.value: factors.append(sentence[f] == v or str(sentence[f]) == str(v)) + if self.before: + factors.append(sentence.time <= self.before) + if self.after: + factors.append(self.after <= sentence.time) if self.checksum is not None: factors.append(sentence.check() == self.checksum) result = functools.reduce(self.reducer, factors) @@ -122,6 +129,13 @@ def likes(self, sentence): return result +def parse_date(string): + if string: + return int(dateutil_parse(string).strftime("%s")) + else: + return None + + @click.command() @click.argument('sources', nargs=-1) @click.option('--mmsi', '-m', multiple=True) @@ -132,12 +146,14 @@ def likes(self, sentence): @click.option('--latitude', '--lat', nargs=2, type=float) @click.option('--field', '-f', multiple=True) @click.option('--value', type=(str, str), multiple=True) +@click.option('--before') +@click.option('--after') @click.option('--checksum', type=click.Choice(['valid', 'invalid'])) @click.option('--mode', type=click.Choice(['and', 'or'])) @click.option('--invert-match', '-v', is_flag=True) @click.option('--verbose', is_flag=True) def grep(sources, mmsi=None, mmsi_file=None, sentence_type=None, vessel_class=None, lon=None, lat=None, - value=None, field=None, checksum=None, + value=None, before=None, after=None, field=None, checksum=None, mode='and', invert_match=False, verbose=False): """ Filters AIS transmissions. """ if not mmsi: @@ -149,7 +165,8 @@ def grep(sources, mmsi=None, mmsi_file=None, sentence_type=None, vessel_class=No checksum_desire = None else: checksum_desire = checksum == "valid" - taster = Taster(mmsi, sentence_type, vessel_class, lon, lat, field, value, mode, checksum_desire, invert_match) + taster = Taster(mmsi, sentence_type, vessel_class, lon, lat, field, value, parse_date(before), parse_date(after), + mode, checksum_desire, invert_match) with wild_disregard_for(BrokenPipeError): for sentence in sentences_from_sources(sources, log_errors=verbose): if taster.likes(sentence): diff --git a/tests/test_tools.py b/tests/test_tools.py index 4045b5e..3f5a06a 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -330,6 +330,18 @@ def test_checksum_filter(self): self.assertFalse(taster.likes(good)) self.assertTrue(taster.likes(bad)) + def test_time_filter(self): + early, late = parse(["1456572038.584 !AIVDM,1,1,,A,35DQ`v100211@E:GFlh=6To`<,0*59", + "1463812839.417 !AIVDM,1,1,,A,15DQ`v001P005W4EqMD`DVW>0>`<,0*62"]) + + taster = Taster(before=1460000000) + self.assertTrue(taster.likes(early)) + self.assertFalse(taster.likes(late)) + + taster = Taster(after=1460000000) + self.assertFalse(taster.likes(early)) + self.assertTrue(taster.likes(late)) + def test_invert_match(self): taster = Taster(lat=(32, 35), invert_match=True) # LA self.assertFalse(taster.likes(self.type_1_la))