How to check if a list of intervals (Joda-Time) fully covers a month in Java

蹲街弑〆低调 提交于 2019-12-21 17:37:05

问题


I'm using Joda-Time library in Java to keep track a list of time intervals. I want to check if a list of Interval objects fully covers every minute of a month. There's about 30 intervals of varying length from a few hours to a few days.

I thought a cheap way to do this is to sort the list of intervals by start time, then successively check if there is a break between the intervals within the range of the month. If yes, then the month is not fully covered.

I'm stuck on the first part, sorting the list. I planned to use Arrays.sort(), but it needs the elements to implement the comparable interface. However, after looking through the source, Joda-Time's Interval class doesn't seem to have one I can override, and I can't extend it to write my own compareTo method.

Other than writing my own sorting method, anyone know an easier way to accomplish this? Thanks


回答1:


You can use next method

static boolean covers(Interval month, List<Interval> intervals)
{
  //assumes intervals are sorted already on start times
  final MutableInterval monthInterval = new MutableInterval(month);
  start: for (final Interval interval : intervals)
  {
     if (interval.getStartMillis() <= monthInterval.getStartMillis()
        && interval.getEndMillis() > monthInterval.getStartMillis())
     {
        if (interval.getEndMillis() > monthInterval.getEndMillis())
        {
           return true;
        }
        monthInterval.setStartMillis(interval.getEndMillis());
        // continue start;  // loop continues regardless
     } else {
           if (interval.overlaps(month)) return false;
     }
  }
  return monthInterval.getStartMillis()== monthInterval.getEndMillis();
} 

Example

   static final List<Interval> intervals = new ArrayList<Interval>();
   static
   {
      intervals.add(new Interval(new DateTime(1990, 05, 15, 00, 00, 00, 00), new DateTime(1990, 05, 18, 00, 00, 00, 00)));
      intervals.add(new Interval(new DateTime(1990, 04, 28, 00, 00, 00, 00), new DateTime(1990, 05, 18, 00, 00, 00, 00)));
      intervals.add(new Interval(new DateTime(1990, 05, 17, 00, 00, 00, 00), new DateTime(1990, 05, 21, 00, 00, 00, 00)));
      intervals.add(new Interval(new DateTime(1990, 05, 21, 00, 00, 00, 00), new DateTime(1990, 05, 29, 00, 00, 00, 00)));
      intervals.add(new Interval(new DateTime(1990, 05, 22, 00, 00, 00, 00), new DateTime(1990, 05, 25, 00, 00, 00, 00)));
      intervals.add(new Interval(new DateTime(1990, 05, 27, 00, 00, 00, 00), new DateTime(1990, 06, 02, 00, 00, 00, 00)));
   }

   public static void main(String[] args)
   {
      final DateTime startOfMonth = new DateTime(1990, 05, 01, 00, 00);
      final Interval monthInterval = new Interval(startOfMonth, startOfMonth.plusMonths(1));

      covers(monthInterval, intervals);
   }

   static boolean covers(Interval month, List<Interval> intervals)
   {
      final MutableInterval monthInterval = new MutableInterval(month);
      start: for (final Interval interval : intervals)
      {
         if (interval.getStartMillis() <= monthInterval.getStartMillis()
            && interval.getEndMillis() > monthInterval.getStartMillis())
         {
            if (interval.getEndMillis() > monthInterval.getStartMillis())
            {
               return true;
            }
            monthInterval.setStartMillis(interval.getEndMillis());
            continue start;
         }
      }
      return monthInterval.getStartMillis()== monthInterval.getEndMillis();
   }



回答2:


You can use Collections#sort with a Comparator to sort the time intervals and use Interval#gap to check for gaps. The following code returns true if the interval between start and end is fully covered by the timeIntervals:

public static boolean isCovered(List<Interval> timeIntervals, DateTime start, DateTime end) {
    if (timeIntervals.isEmpty()) {
        return false;
    }

    // create sorted set from original List to get
    // sorted intervals without double entries
    Set<Interval> intervalSet = new TreeSet<>(new Comparator<Interval>() {
        @Override
        public int compare(Interval o1, Interval o2) {
            return o1.getStart().compareTo(o2.getStart());
        }
    });
    intervalSet.addAll(timeIntervals);

    List<Interval> intervals = new ArrayList<>(intervalSet);

    // remove intervals completely contained in others
    List<Interval> removedIntervals = new ArrayList<>();
    for (int i = 0; i < (intervals.size()-1); i++) {
        for (int j = (i+1); j < intervals.size(); j++) {
            if (intervals.get(i).contains(intervals.get(j))) {
                if (!removedIntervals.contains(intervals.get(j))) {
                    removedIntervals.add(intervals.get(j));
                }
            }
        }
    }
    intervals.removeAll(removedIntervals);

    if (intervals.get(0).getStart().isAfter(start) ||
            intervals.get(intervals.size() - 1).getEnd().isBefore(end)) {
        return false;
    }

    // check for gaps
    for (int i = 0; i < (intervals.size() - 1); i++) {
    Interval gap = intervals.get(i).gap(intervals.get(i+1));
        if (gap != null && new Interval(start, end).overlaps(gap)) {
            // gap detected between interval i and interval (i+1)
            return false;
        }
    }

    return true;
}


来源:https://stackoverflow.com/questions/20679957/how-to-check-if-a-list-of-intervals-joda-time-fully-covers-a-month-in-java

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!