public static <T> NavigableSet<Point<T>> fastKNearestPoints(SortedSet<Point<T>> points, Instant time, int k) {

        checkNotNull(points, "The input SortedSet of Points cannot be null");
        checkNotNull(time, "The input time cannot be null");
        checkArgument(k >= 0, "k (" + k + ") must be non-negative");

        if (k >= points.size()) {
            return newTreeSet(points);
        }

        Point<T> stub = points.first();
        Point<T> searchPoint = Point.builder(stub).time(time).latLong(0.0, 0.0).build();

        //create two iterators, one goes up from the searchPoint, one goes down from the searchPoint
        NavigableSet<Point<T>> headSet = ((NavigableSet<Point<T>>) points).headSet(searchPoint, true);
        NavigableSet<Point<T>> tailSet = ((NavigableSet<Point<T>>) points).tailSet(searchPoint, false);
        Iterator<Point<T>> headIter = headSet.descendingIterator();
        Iterator<Point<T>> tailIter = tailSet.iterator();

        TreeSet<Point<T>> results = newTreeSet();
        Point<T> up = (headIter.hasNext()) ? headIter.next() : null;
        Point<T> down = (tailIter.hasNext()) ? tailIter.next() : null;

        while (results.size() < k) {
            //add an element from the "down set" when we are out of elements in the "up set"
            if (up == null) {
                results.add(down);
                down = tailIter.next();
                continue;
            }
            //add an element from the "up set" when we are out of elements in the "down set"
            if (down == null) {
                results.add(up);
                up = headIter.next();
                continue;
            }
            //add the nearest point when we can choose between the "up set" and the "down set"
            Duration upDistance = Duration.between(up.time(), time);
            Duration downDistance = Duration.between(time, down.time());

            if (theDuration(upDistance).isLessThanOrEqualTo(downDistance)) {
                results.add(up);
                up = (headIter.hasNext()) ? headIter.next() : null;
            } else {
                results.add(down);
                down = (tailIter.hasNext()) ? tailIter.next() : null;
            }
        }

        return results;
    }
@Test
    public void testFastKNearestPoints_7() {
        NavigableSet<Point<String>> knn = fastKNearestPoints(points, EPOCH.plusSeconds(5), 0);
        assertEquals(0, knn.size());
        assertEquals(12, points.size());
    }