I do not have a complete answer, but I have some suggestions.
Timezone
A Date represents date-time in UTC / GMT, i.e. without a time zone offset. Your values are in the time zone. In the end, you will feel better without ignoring this time zone. Adjust your values. As a rule, think, work and store dates in UTC / GMT. Convert to local time as needed for presentation in the user interface.
While java.util.Date does not have a time zone, the Joda-Time DateTime (discussed below) really knows its own time zone and time zone.
Avoid java.util.Date/Calendar
The java.util.Date and Calendar classes bundled with Java are known to be unpleasant. Avoid them.
Instead, use either:
Do not think of Joda-Time as any old "extra library". The first thing I do when creating a new project in my development environment is to add the Joda-Time library. This is just fine. Or juDate / Calendar is just so bad, depending on your perspective.
Enable Launch, End Exclusive
The best way to deal with a time period is to make the initial inclusion and ending exclusive. Write the logic where you test MORE, THAN OR UNIFORMLY, to the beginning and LESS than the end (not testing for peers at the end). I discuss this in yet another answer along with a chart.
Joda time
Joda-Time offers these classes to determine the time span: Period, Duration, and Internal. Clocks and similar classes offer some useful utility methods.
Find spaces
If your goal is to make a list of spaces, time intervals when a class is not assigned to a class, then the obvious way that seems to me is to sort the classes chronologically (and by class), as in the answer of Rob Whiteside . Define the “available” time period when its beginning ends with the previous class, and its end is the beginning of the next class. I have no experience in this area, so there may be a smarter way.
See this question on sorting a list of intervals.
Code example
Here is sample code using Joda-Time 2.3.
Specify the time zone, not rely on the default value ...
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
Create three classes as sample data in random order ...
Interval class_math = new Interval( new DateTime( 2014, 1, 24, 10, 0, 0, timeZone ), new DateTime( 2014, 1, 24, 11, 15, 0, timeZone ) ); Interval class_chemistry = new Interval( new DateTime( 2014, 1, 24, 8, 0, 0, timeZone ), new DateTime( 2014, 1, 24, 9, 15, 0, timeZone ) ); Interval class_french_lit = new Interval( new DateTime( 2014, 1, 24, 13, 0, 0, timeZone ), new DateTime( 2014, 1, 24, 14, 15, 0, timeZone ) );
Collect sample data into a list ...
java.util.List<Interval> classes = new java.util.ArrayList<Interval>( 3 ); classes.add( class_math ); classes.add( class_chemistry ); classes.add( class_french_lit ); System.out.println( "classes unsorted: " + classes );
Sorting a list using a custom Comparator (see class definition below) ...
java.util.Collections.sort( classes, new IntervalStartComparator() ); System.out.println( "classes sorted: " + classes );
Create a collection of objects representing each space between the found classes ...
java.util.List<Interval> gaps = new java.util.ArrayList<Interval>(); DateTime gapStart = null, gapStop = null; for ( int i = 0; i < classes.size(); i++ ) {
The class definition for Comparator used in the code above and taken from this answer by John Skeet ...
class IntervalStartComparator implements java.util.Comparator<Interval> { @Override public int compare( Interval x, Interval y ) { return x.getStart().compareTo( y.getStart() ); } }
At startup ...
classes unsorted: [2014-01-24T10:00:00.000+01:00/2014-01-24T11:15:00.000+01:00, 2014-01-24T08:00:00.000+01:00/2014-01-24T09:15:00.000+01:00, 2014-01-24T13:00:00.000+01:00/2014-01-24T14:15:00.000+01:00] classes sorted: [2014-01-24T08:00:00.000+01:00/2014-01-24T09:15:00.000+01:00, 2014-01-24T10:00:00.000+01:00/2014-01-24T11:15:00.000+01:00, 2014-01-24T13:00:00.000+01:00/2014-01-24T14:15:00.000+01:00] gaps: [2014-01-24T09:15:00.000+01:00/2014-01-24T10:00:00.000+01:00, 2014-01-24T11:15:00.000+01:00/2014-01-24T13:00:00.000+01:00]
Duration
You said you take care of the breaks for at least 15 minutes. A Duration instance in Joda-Time represents milliseconds between the start and end points of an interval.
Here is some unverified code outside my head.
Renamed the “gap” var from above to “gapInterval” to remind you that this is Interval .
Note that Minutes is a class. The "Minutes" var shown below is an instance of a non- integer primitive ("int"). A call to the getMinutes method displays an int primitive.
Duration duration = gapInterval.toDuration(); Minutes minutes = duration.toStandardMinutes();
ISO 8601
String outputs you see that they are not arbitrary. This is ISO 8601 . This convenient standard defines string representations of single values for date and time , as well as the <start>/<end> time interval .
This standard also defines a string representation of durations that may be useful to you in the PnYnMnDTnHnMnS format, for example, "P3Y6M4DT12H30M5S", which means "three years, six months, four days, twelve hours, thirty minutes and five seconds." Or in short, as in your case, the class can be PT1H15M for one and a quarter hours.
Joda-Time uses ISO 8601 by default for most of all, both for inputs and outputs.