Skip to content
Advertisement

Creating a list of avalible Timeslots based on a list LocalDateTime objects and a List of taken Timeslots with Streams

I have a List<Timeslot> that contains entity Timeslot with the following fields:

  1. timeslot_id;
  2. day;
  3. start_time;
  4. end_time.

For example, this list contains two records:

  • start_time of the first record equals 9:00 and end_time equals 10:00.

  • start_time of second object equals 10:00 and end_time equals 11:00.

And the second list contains timestamps List<LocalDateTime>:

[2022-04-16T08:00, 2022-04-16T09:00, 2022-04-16T10:00, 2022-04-16T11:00, 
 2022-04-16T12:00, 2022-04-16T13:00, 2022-04-16T14:00, 2022-04-16T15:00]

I need to create a third List<Timeslot> that will contain Timeslots except this two from the first list.

In this case, as a result, the third list should contain six objects of Timeslot class.

start_time of first should equal 2022-04-16T08:00 and end_time 2022-04-16T09:00. I.e. the difference between start_time and end_time for every other timeslot is one hour.

So, the result constructed from the list of timestamps provided above should contain six objects:

  • start_time is 8:00, end_time is 9:00.
  • start_time is 11:00, end_time is 12:00.
  • start_time is 12:00, end_time is 13:00 … and so on.

I the objects for with start_time 9:00 and 10:00 will not be present in the third list because they are booked already (present in the first list).

I tried to create the third list using Java Streams, which should compare fields start_time and end_time with timestamps from the second list.

I’ve tried this, but the resulting list is always empty:

List<Timeslot> availableSlots = query.stream()
    .filter(timeslot -> timestamps.contains(timeslot.getStartTime()))
    .toList();

Timeslot class:

@Entity(name = "timeslot")
public class Timeslot {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "timeslot_id")
    private Integer id;
    @Column(name = "day", columnDefinition = "DATE")
    private LocalDateTime day;
    @Column(name = "start_time")
    private LocalDateTime startTime;
    @Column(name = "end_time")
    private LocalDateTime endTime;
    @Column(name = "user_id")
    private Integer userId;
    @Column(name = "is_recorded")
    private Boolean isRecorded;
}

Advertisement

Answer

I’ve simplified your Timeslot class for this problem (for demonstration purposes) since for this task you primarily concern about the start time and end time of each timeslot.

My approach is to create a set of LocalDateTime objects by extracting the start time from each timeslot that is already taken (represented by your first list).

Then create a stream over the query list and filter the date-time object that are not present in the set. Then create a timeslot using each date-time object as a start time (end time = start time + 1 hour). And collect all the stream elements into a list.

Note: terminal operation toList() creates an immutable list, you can obtain a mutable list by applying collect(Collectors.toList()) instead.

public static void main(String[] args) {
    List<LocalDateTime> query =
        List.of(LocalDateTime.of(2022, 04, 16, 8, 00),
                LocalDateTime.of(2022, 04, 16, 9, 00),
                LocalDateTime.of(2022, 04, 16, 10, 00),
                LocalDateTime.of(2022, 04, 16, 11, 00),
                LocalDateTime.of(2022, 04, 16, 12, 00),
                LocalDateTime.of(2022, 04, 16, 13, 00),
                LocalDateTime.of(2022, 04, 16, 14, 00),
                LocalDateTime.of(2022, 04, 16, 15, 00));

    List<Timeslot> timeslots = // timeslots that already taken
        List.of(new Timeslot(LocalDateTime.of(2022, 04, 16, 9, 00),
                             LocalDateTime.of(2022, 04, 16, 10, 00)),
                new Timeslot(LocalDateTime.of(2022, 04, 16, 10, 00),
                             LocalDateTime.of(2022, 04, 16, 11, 00)));
    
    Set<LocalDateTime> takenStartTime = timeslots.stream()
        .map(Timeslot::getStartTime)
        .collect(Collectors.toSet());

    List<Timeslot> availableSlots = query.stream()
        .filter(dateTime -> !takenStartTime.contains(dateTime))
        .map(dateTime -> new Timeslot(dateTime, dateTime.plusHours(1)))
        .toList();
    
    availableSlots.forEach(System.out::println);
}

Simplified dummy Timeslot class

public class Timeslot {
    private LocalDateTime startTime;
    private LocalDateTime endTime;
    
    // constructor, getters, toString()
}

Output

Timeslot{start_time=2022-04-16T08:00, end_time=2022-04-16T09:00}
Timeslot{start_time=2022-04-16T11:00, end_time=2022-04-16T12:00}
Timeslot{start_time=2022-04-16T12:00, end_time=2022-04-16T13:00}
Timeslot{start_time=2022-04-16T13:00, end_time=2022-04-16T14:00}
Timeslot{start_time=2022-04-16T14:00, end_time=2022-04-16T15:00}
Timeslot{start_time=2022-04-16T15:00, end_time=2022-04-16T16:00}
Advertisement