0

I have encountered a problem that I don't know how to solve.

I have a list containing dates, as below code:

public static void main(String[] args) {
    TreeSet<LocalDate> dates = getDaysBetween("2017-02-01","2017-03-31");
    dates.removeAll(getDaysBetween("2017-01-01","2017-02-01"));
    dates.removeAll(getDaysBetween("2017-03-01","2017-03-04"));
    dates.removeAll(getDaysBetween("2017-03-08","2017-03-08"));
    dates.removeAll(getDaysBetween("2017-03-10","2017-03-12"));
    dates.removeAll(getDaysBetween("2017-03-14","2017-03-16"));
    dates.removeAll(getDaysBetween("2017-03-19","2017-03-19"));
    dates.removeAll(getDaysBetween("2017-03-22","2017-03-22"));
}

public static TreeSet<LocalDate> getDaysBetween(String start, String end){
    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    LocalDate startDate = LocalDate.parse(start, fmt);
    LocalDate endDate = LocalDate.parse(end, fmt);
    TreeSet<LocalDate> dates = new TreeSet<LocalDate>();
    LocalDate current = startDate;
    while (current.isBefore(endDate) || current.equals(endDate)) {
       dates.add(current);
       current = current.plusDays(1);
    }
    return dates;
 }

 class Period {
     private Date startDate;
     private Date endDate;
 }

The criteria for start and end dates are "dates are consecutive (one day of difference between them)", and when they're not consecutive, then another period has started.

In main method, I create a lot dates stored into List, and then remove some dates from that list. Using the left consecutive dates (one day of difference between them) in the list to create a period, and when they're not consecutive, then another period has started.

The periods as follows:

startDate: 2017-02-02, endDate: 2017-02-28
startDate: 2017-03-05, endDate: 2017-03-07
startDate: 2017-03-09, endDate: 2017-03-09
startDate: 2017-03-13, endDate: 2017-03-13
startDate: 2017-03-17, endDate: 2017-03-18
startDate: 2017-03-20, endDate: 2017-03-21
startDate: 2017-03-23, endDate: 2017-03-31

I want to create an algorithm to create these Period objects according to the provided date list.

I'm blocked by this for long time. So far, I have not come up with a good sulotion for this case.

Carl
  • 43
  • 3
  • 2
    What is your input, could you please share whatever you did ? – Alpesh Jikadra Mar 19 '18 at 12:28
  • How do you identify the start and end dates of each periods? – Alexandre Dupriez Mar 19 '18 at 12:47
  • Here your total input is 11 dates and your Class object contains 2 field, so how do you want to distribute remaining parameter value ? – Alpesh Jikadra Mar 19 '18 at 13:27
  • Single quotes aren't Java syntax, neither are the brackets `[]`, so is this read from a file, is it encapsulated in a String or what is it? – user unknown Mar 19 '18 at 14:03
  • 1
    Excuse me, you don’t want to use the `Date` class. It is long outdated, and [java.time, the modern Java date and time API,](https://docs.oracle.com/javase/tutorial/datetime/) is so much nicer to work with. So you should want to use its `LocalDate` class instead. It’s a date without time of day, which seems to match your requirements better. – Ole V.V. Mar 19 '18 at 14:16

1 Answers1

3

I'm assuming that the criteria for start and end dates are "dates are consecutive (one day of difference between them)", and when they're not consecutive, then another period has started. I'm also assuming, based on your input, that the list of dates are already sorted.

First of all, you could change your code to use java.time API, instead of old java.util.Date. If you're using Java 7 or below, use the threenten backport, which has the same classes and functionality.

So the first thing is to define if you care about the time or not. In your inputs, all times are midnight. If that doesn't make difference, you can use a LocalDate, which is a class that cares only about the day, month and year.

I'm assuming that the time-of-the-day must be kept, so I'm using a LocalDateTime (a class that has date and time, so it exactly matches your inputs):

class Period {
    private LocalDateTime startDate;
    private LocalDateTime endDate;

    // constructor, getters and setters
}

Now we must loop throuh the list and convert those strings to LocalDateTime. This can be done using a DateTimeFormatter. Then we compare the dates to see if they are consecutive or not - using the criteria "difference between them is one day or more" - and I'm using the ChronoUnit class to calculate that difference.

I'm using this dates list:

String[] datesList = new String[] {
    "2018-03-01 00:00:00",
    "2018-03-02 00:00:00",
    "2018-03-03 00:00:00",
    "2018-03-04 00:00:00",
    "2018-03-10 00:00:00",
    "2018-03-11 00:00:00",
    "2018-03-12 00:00:00",
    "2018-03-14 00:00:00",
    "2018-03-15 00:00:00",
    "2018-03-16 00:00:00",
    "2018-03-18 00:00:00" };

And the algorithm is something like this:

List<Period> periodList = new ArrayList<>();
Period p = null;
LocalDateTime prev = null;
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (String s : datesList) {
    if (prev == null) { // starting new period 
        prev = LocalDateTime.parse(s, fmt);
        p = new Period();
        p.setStartDate(prev);
    } else { // in the middle of a period
        LocalDateTime date = LocalDateTime.parse(s, fmt);
        // check the difference in days
        // convert to LocalDate to ignore hours in the comparison
        if (ChronoUnit.DAYS.between(prev.toLocalDate(), date.toLocalDate()) > 1) {
            // difference is more than 1 day, period ended
            p.setEndDate(prev);
            periodList.add(p);

            // start new period
            p = new Period();
            p.setStartDate(date);
            prev = date;
        } else {
            prev = date;
        }
    }
}
// check last period
if (p != null && p.getEndDate() == null) {
    p.setEndDate(p.getStartDate());
    periodList.add(p);
}

As I assumed lots of things, you must adapt this according to your criteria.

If you still need to work with java.util.Date, you can convert it: Convert java.time.LocalDate into java.util.Date type

ashtadd
  • 48
  • 3
  • Thanks! Help me a lot. The issue is fixed by your solution. And your assumptions is what I want to express. @ashtadd – Carl Mar 20 '18 at 05:25