Split Date-time Range into Equal Intervals in Java

In this Java date-time tutorial, we’ll explore how to split a date-time range into equal intervals. Conceptually, splitting a date-time range into equal intervals involves dividing the entire range into smaller, equally-sized sub-ranges. In short, we need to determine the start and end points of each sub-range.

1. Splitting Date-time Range to N Equal Intervals

Let us start with a simple example where we have a start date and end date, and we want to divide the range into N equal intervals. Each interval is equally spaced time-slice with milliseconds precision.

In our Java program, we have used LocalDateTime to mark start and end points, you can use any other class of your choice of requirement.

public static List<LocalDateTime> splitDateTimeRangeInEqualIntervals(
    LocalDateTime start, LocalDateTime end, int n) {

  Duration range = Duration.between(start, end);
  Duration interval = range.dividedBy(n - 1);
  List<LocalDateTime> listOfDates = new ArrayList<>();
  LocalDateTime timeline = start;
  for (int i = 0; i < n - 1; i++) {
    listOfDates.add(timeline);
    timeline = timeline.plus(interval);
  }
  listOfDates.add(end);
  return listOfDates;
}

The above method takes three parameters: start (the starting point of the range), end (the ending point of the range), and n (the number of intervals to split the range into). It returns the List containing the split date-time intervals.

We first calculate the total duration between start and end points using the Duration.between() method and then calculate the interval duration by dividing the total range duration by the number of intervals minus one. Finally, we increment the timeline by the interval duration and capture the specific LocalDateTime instance at that point.

We can use the splitDateTimeRangeInEqualIntervals() as follows:

int equalParts = 15;
LocalDateTime start = LocalDateTime.of(2021, 10, 1, 0, 0, 0);
LocalDateTime end = LocalDateTime.of(2022, 03, 31, 0, 0, 0);

List<LocalDateTime> intervals = splitDateTimeRangeInEqualIntervals(start, end, equalParts);

2. Splitting Date-time Range in Date Parts

Several times we may need to split a date-time range in such a way that each sub-range contains a specific date-part such as day, week, month, or year. This can be needed in batch applications where you want to split the records based on time-intervals and process the records in smaller batches.

No matter what type of range it is, the process to find all the sub-intervals remains the same. We start with the starting point and incrementally add the specific interval (day, month, year, etc) until we reach the ending point. We collect all these intermediate timestamps in a List that represents the sub-ranges.

2.1. Split Date-time Range into Days

The following Java program uses LocalDate.plusDays() method to step through the date ranges split by days.

public static List<LocalDate> split_LocalDate_Range_Into_Days(
    LocalDate startDate, LocalDate endDate) {

  long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate);
  return IntStream.iterate(0, i -> i + 1)
    .limit(numOfDaysBetween)
    .mapToObj(i -> startDate.plusDays(i))
    .collect(Collectors.toList());
}

2.2. Split Date-time Range into Months

The following Java program uses LocalDate.plusMonths() method to step through the date ranges split by months. We collect each sub-range point as an instance of YearMonth where months range from 1 to 12.

We are intentionally learning the day, hour, or minute parts as we are not interested in them.

We are intentionally learning the day, hour or minute parts as we are not interersted in them.

public static List<YearMonth> split_LocalDate_Range_Into_Months(
  LocalDate startDate, LocalDate endDate) {

	long numOfDaysBetween = ChronoUnit.MONTHS.between(startDate, endDate);
	return IntStream.iterate(0, i -> i + 1)
	    .limit(numOfDaysBetween)
	    .mapToObj(i -> YearMonth.from(startDate.plusMonths(i)))
	    .collect(Collectors.toList());
}

2.3. Split Date-time Range into Years

Similar to the previous program, we can split the date-time range into years. We collect the range into Year class and use LocalDate.plusYears() method to step through the range.

public static List<Year> split_LocalDate_Range_Into_Years(
    LocalDate startDate, LocalDate endDate) {

  long numOfDaysBetween = ChronoUnit.YEARS.between(startDate, endDate);
  return IntStream.iterate(0, i -> i + 1)
      .limit(numOfDaysBetween)
      .mapToObj(i -> Year.from(startDate.plusYears(i)))
      .collect(Collectors.toList());
} 

2.4. Split Date-time Range into Weeks

Splitting the date-time range into weeks is not a straightforward process because we do not have an exact representation of the week as we have for months, years, and other time parts.

For this reason, we start with creating a new record that can store the week and year information to represent a specific week of a specific year.

record YearWeek(int year, int week) {
 //...
}

Next, similar to other JDK classes, we will add a factory method that will validate the inputs and return a valid instance of YearWeek record. Additionally, add a toString() which helps in logging and debugging.

record YearWeek(int year, int week) {

  public static YearWeek from(TemporalAccessor temporal) {
    Objects.requireNonNull(temporal, "temporal");
    try {
      if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
        temporal = LocalDate.from(temporal);
      }
      return new YearWeek(temporal.get(YEAR), temporal.get(ALIGNED_WEEK_OF_YEAR));
    } catch (DateTimeException ex) {
      throw new DateTimeException(
          STR."Unable to obtain YearWeek from TemporalAccessor: \{temporal} of type \{temporal.getClass().getName()}", ex);
    }
  }

  @Override
  public String toString() {
    return STR."\{year}-\{week}";
  }
}

Next, we are ready to modify the previous logic and use LocalDate.plusWeeks() method to step through the weeks.

public static List<YearWeek> split_LocalDate_Range_Into_Weeks(
    LocalDate startDate, LocalDate endDate) {

  long numOfDaysBetween = ChronoUnit.WEEKS.between(startDate, endDate);
  return IntStream.iterate(0, i -> i + 1)
      .limit(numOfDaysBetween)
      .mapToObj(i -> YearWeek.from(startDate.plusWeeks(i)))
      .collect(Collectors.toList());
}

3. Conclusion

This short Java tutorial discusses different methods to split a given time duration (start and end dates) into N equally spaced intervals. We also learned to obtain the intervals in the form of date parts which are generally useful in processing batch records.

Happy Learning !!

Source Code on Github

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.