How to compare instanced DateTime objects?












0















I'm writing a program to sort datetimes by date.
There is a DateTime beginning and a DateTime end.
These are put into their own object from user input.
The DateTime beginning and the DateTime end make up their own term.
So each term has an object of its own with a DateTime beginning and a DateTime end.



What I want to do is to sort all DateTime beginning and all DateTime end by date.
How can I do this? I'm thinking about a comperator but I can't seem to do this on custom objects.



So lets say user imputs one beginning date of 01/01/2000 and one end date of 01/01/2002. This makes up one term.
The user then imputs a second term consisting of a beginning date of 01/01/2001 and an end date of 01/01/2003.



What I now want to do is to sort the dates and make the three new terms which would be:



beginning 01/01/2000 end 01/01/2001

beginning 01/01/2001 end 01/01/2002

beginning 01/01/2002 end 01/01/2003


I'm stuck on how to proceed with this, any ideas?










share|improve this question

























  • Have a look at LocalDateTime which implements Comparable and has many useful features. Your question looks like you also want to know LocalDate, if time of day does not matter in your use case. Try out some code, then if stuck, ask another question here with a specific code problem.

    – deHaar
    Nov 13 '18 at 15:24











  • Just implement comparable interface? Take a look at this: stackoverflow.com/questions/21626439/…

    – Alexxx
    Nov 13 '18 at 15:24











  • Why are there 3 terms if you only input 2 terms?

    – LunaticJape
    Nov 13 '18 at 15:30











  • Share the class that holds your Begin and End, and the code you made to solve this

    – azro
    Nov 13 '18 at 15:34











  • I think some more examples, using year ranges with larger spreads, would be useful. Do you want to create a term for each year in any of the ranges input by the user?

    – VGR
    Nov 13 '18 at 15:39
















0















I'm writing a program to sort datetimes by date.
There is a DateTime beginning and a DateTime end.
These are put into their own object from user input.
The DateTime beginning and the DateTime end make up their own term.
So each term has an object of its own with a DateTime beginning and a DateTime end.



What I want to do is to sort all DateTime beginning and all DateTime end by date.
How can I do this? I'm thinking about a comperator but I can't seem to do this on custom objects.



So lets say user imputs one beginning date of 01/01/2000 and one end date of 01/01/2002. This makes up one term.
The user then imputs a second term consisting of a beginning date of 01/01/2001 and an end date of 01/01/2003.



What I now want to do is to sort the dates and make the three new terms which would be:



beginning 01/01/2000 end 01/01/2001

beginning 01/01/2001 end 01/01/2002

beginning 01/01/2002 end 01/01/2003


I'm stuck on how to proceed with this, any ideas?










share|improve this question

























  • Have a look at LocalDateTime which implements Comparable and has many useful features. Your question looks like you also want to know LocalDate, if time of day does not matter in your use case. Try out some code, then if stuck, ask another question here with a specific code problem.

    – deHaar
    Nov 13 '18 at 15:24











  • Just implement comparable interface? Take a look at this: stackoverflow.com/questions/21626439/…

    – Alexxx
    Nov 13 '18 at 15:24











  • Why are there 3 terms if you only input 2 terms?

    – LunaticJape
    Nov 13 '18 at 15:30











  • Share the class that holds your Begin and End, and the code you made to solve this

    – azro
    Nov 13 '18 at 15:34











  • I think some more examples, using year ranges with larger spreads, would be useful. Do you want to create a term for each year in any of the ranges input by the user?

    – VGR
    Nov 13 '18 at 15:39














0












0








0








I'm writing a program to sort datetimes by date.
There is a DateTime beginning and a DateTime end.
These are put into their own object from user input.
The DateTime beginning and the DateTime end make up their own term.
So each term has an object of its own with a DateTime beginning and a DateTime end.



What I want to do is to sort all DateTime beginning and all DateTime end by date.
How can I do this? I'm thinking about a comperator but I can't seem to do this on custom objects.



So lets say user imputs one beginning date of 01/01/2000 and one end date of 01/01/2002. This makes up one term.
The user then imputs a second term consisting of a beginning date of 01/01/2001 and an end date of 01/01/2003.



What I now want to do is to sort the dates and make the three new terms which would be:



beginning 01/01/2000 end 01/01/2001

beginning 01/01/2001 end 01/01/2002

beginning 01/01/2002 end 01/01/2003


I'm stuck on how to proceed with this, any ideas?










share|improve this question
















I'm writing a program to sort datetimes by date.
There is a DateTime beginning and a DateTime end.
These are put into their own object from user input.
The DateTime beginning and the DateTime end make up their own term.
So each term has an object of its own with a DateTime beginning and a DateTime end.



What I want to do is to sort all DateTime beginning and all DateTime end by date.
How can I do this? I'm thinking about a comperator but I can't seem to do this on custom objects.



So lets say user imputs one beginning date of 01/01/2000 and one end date of 01/01/2002. This makes up one term.
The user then imputs a second term consisting of a beginning date of 01/01/2001 and an end date of 01/01/2003.



What I now want to do is to sort the dates and make the three new terms which would be:



beginning 01/01/2000 end 01/01/2001

beginning 01/01/2001 end 01/01/2002

beginning 01/01/2002 end 01/01/2003


I'm stuck on how to proceed with this, any ideas?







java datetime






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 13 '18 at 16:11









Mark Rotteveel

59.7k1476119




59.7k1476119










asked Nov 13 '18 at 15:19









JB1989JB1989

92




92













  • Have a look at LocalDateTime which implements Comparable and has many useful features. Your question looks like you also want to know LocalDate, if time of day does not matter in your use case. Try out some code, then if stuck, ask another question here with a specific code problem.

    – deHaar
    Nov 13 '18 at 15:24











  • Just implement comparable interface? Take a look at this: stackoverflow.com/questions/21626439/…

    – Alexxx
    Nov 13 '18 at 15:24











  • Why are there 3 terms if you only input 2 terms?

    – LunaticJape
    Nov 13 '18 at 15:30











  • Share the class that holds your Begin and End, and the code you made to solve this

    – azro
    Nov 13 '18 at 15:34











  • I think some more examples, using year ranges with larger spreads, would be useful. Do you want to create a term for each year in any of the ranges input by the user?

    – VGR
    Nov 13 '18 at 15:39



















  • Have a look at LocalDateTime which implements Comparable and has many useful features. Your question looks like you also want to know LocalDate, if time of day does not matter in your use case. Try out some code, then if stuck, ask another question here with a specific code problem.

    – deHaar
    Nov 13 '18 at 15:24











  • Just implement comparable interface? Take a look at this: stackoverflow.com/questions/21626439/…

    – Alexxx
    Nov 13 '18 at 15:24











  • Why are there 3 terms if you only input 2 terms?

    – LunaticJape
    Nov 13 '18 at 15:30











  • Share the class that holds your Begin and End, and the code you made to solve this

    – azro
    Nov 13 '18 at 15:34











  • I think some more examples, using year ranges with larger spreads, would be useful. Do you want to create a term for each year in any of the ranges input by the user?

    – VGR
    Nov 13 '18 at 15:39

















Have a look at LocalDateTime which implements Comparable and has many useful features. Your question looks like you also want to know LocalDate, if time of day does not matter in your use case. Try out some code, then if stuck, ask another question here with a specific code problem.

– deHaar
Nov 13 '18 at 15:24





Have a look at LocalDateTime which implements Comparable and has many useful features. Your question looks like you also want to know LocalDate, if time of day does not matter in your use case. Try out some code, then if stuck, ask another question here with a specific code problem.

– deHaar
Nov 13 '18 at 15:24













Just implement comparable interface? Take a look at this: stackoverflow.com/questions/21626439/…

– Alexxx
Nov 13 '18 at 15:24





Just implement comparable interface? Take a look at this: stackoverflow.com/questions/21626439/…

– Alexxx
Nov 13 '18 at 15:24













Why are there 3 terms if you only input 2 terms?

– LunaticJape
Nov 13 '18 at 15:30





Why are there 3 terms if you only input 2 terms?

– LunaticJape
Nov 13 '18 at 15:30













Share the class that holds your Begin and End, and the code you made to solve this

– azro
Nov 13 '18 at 15:34





Share the class that holds your Begin and End, and the code you made to solve this

– azro
Nov 13 '18 at 15:34













I think some more examples, using year ranges with larger spreads, would be useful. Do you want to create a term for each year in any of the ranges input by the user?

– VGR
Nov 13 '18 at 15:39





I think some more examples, using year ranges with larger spreads, would be useful. Do you want to create a term for each year in any of the ranges input by the user?

– VGR
Nov 13 '18 at 15:39












3 Answers
3






active

oldest

votes


















0














Put every date in a new collection, sort it by the date, and then create new objects that consist neighbour dates from the collection.



Try:



public static void main(String args) {
List<YourClass> list = new ArrayList<>();

list.add(new YourClass(new Date(100000000), new Date(200000000)));
list.add(new YourClass(new Date(150000000), new Date(250000000)));
list.add(new YourClass(new Date(50000000), new Date(300000000)));

System.out.println(list);

List<Date> dates = new ArrayList<>();
for (YourClass yc : list){
if (!dates.contains(yc.beginning)) dates.add(yc.beginning);
if (!dates.contains(yc.end)) dates.add(yc.end);
}

Collections.sort(dates);

List<YourClass> list2 = new ArrayList<>();

for (int i=0; i < dates.size() -1; i++){
list2.add(new YourClass(dates.get(i), dates.get(i+1)));
}

System.out.println(list2);

}

public static class YourClass {
Date beginning;
Date end;

public YourClass(Date beginning, Date end) {
this.beginning = beginning;
this.end = end;
}

@Override
public String toString() {
return "n" + beginning + " -> " + end ;
}
}





share|improve this answer
























  • I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdated Date class.

    – Ole V.V.
    Nov 13 '18 at 19:20






  • 1





    Yes, its not best solution, just an illustration of algorithm working. LocalDate class is preferred for workig with date and implements Comparable as like a Date class.

    – Mark
    Nov 13 '18 at 20:01











  • This is doing exactly what I want it to do and half the code I had already. I only added the new Array and sorted it via collections. Thanks for this so far. But I fail to understand why this works. How does the .sort in collections know how I want to sort it exactly?

    – JB1989
    Nov 14 '18 at 7:34













  • Date class, LocalDate class, Integer class and more else classes implement Comparable interface. It means that inside the class discribed the rule how to compare two this class objects. And Sort method use this rule for sorting.

    – Mark
    Nov 14 '18 at 8:02



















1














tl;dr




What I want to do is to sort all DateTime beginning and all DateTime end by date.




You can do one or the other but not both.



To sort by start date (seems sensible in practice), implement compareTo method.



return this.getDateRange().getStart().compareTo( thatStart );


To sort by stop date (I do not see any sense in this), implement the Comparator interface.



return 
t1.getDateRange().getEnd().compareTo(
t2.getDateRange().getEnd()
)
;


LocalDate



As others noted, you should be using the modern java.time classes, never the terrible old Date/Calendar/SimpleDateFormat classes. For a date-only value, without time-of-day and without time zone, use LocalDate.



LocalDateRange



As the Answer by jbx discusses, you should represent your term’s start and stop dates as a pair. But do not write a class when one already exists. Use LocalDateRange class from the ThreeTen-Extra project. This project adds functionality to the java.time classes.



Comparable



On your Term class, implement Comparable interface to enable simple easy sorting. Add the method compareTo. The obvious approach there would be to compare the starting LocalDate of each Term object’s LocalDateRange object.



The LocalDate class implements compareTo, no we don’ have to.



@Override
public int compareTo ( Object o ) {
if ( this == o ) return 0;
if ( o == null || getClass() != o.getClass() ) return 0;
LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
return this.getDateRange().getStart().compareTo( thatStart );
}


See the Java Tutorial on object-ordering.



Sort by stop date



Your Question is not clear, but you seem to be asking to alternatively sort by the ending date. I cannot imagine how this is useful in practical terms. But anyways, the solution is to sort by providing an implementation of the Comparator interface.



    @Override
public int compare ( Term t1 , Term t2 ) {
return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
}


Example class



Here is an example Term class. May not be production-quality code, but should get you going in the right direction.



package com.basilbourque.example;

import org.threeten.extra.LocalDateRange;

import java.time.LocalDate;
import java.time.Month;
import java.util.*;

public class Term implements Comparable {
private UUID id;
private LocalDateRange dateRange;

// Constructor
public Term ( LocalDate start , LocalDate stop , UUID id ) {
Objects.requireNonNull( start ); // TODO: Add more such checks for all arguments.
if ( start.getYear() < 2015 ) { // TODO: Add more such checks for too far into the past or future, for both start and for stop.
throw new IllegalArgumentException( "Year of start date is too far in the past. Message # afcd30a0-b639-4ccf-b064-18cc2ea8587b." );
}
this.id = id;
this.dateRange = LocalDateRange.of( start , stop );
}

// Alternative constructor.
public Term ( LocalDateRange dateRange , UUID id ) {
this( dateRange.getStart() , dateRange.getEnd() , id );
}



// --------| Object |-------------------------
@Override
public String toString ( ) {
return "Term{ " +
"id=" + id +
" | dateRange=" + dateRange +
" }";
}

public UUID getId ( ) {
return id;
}

public LocalDateRange getDateRange ( ) {
return dateRange;
}

@Override
public boolean equals ( Object o ) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
Term term = ( Term ) o;
return this.getId().equals( term.getId() );
}

@Override
public int hashCode ( ) {
return Objects.hash( this.getId() );
}

@Override
public int compareTo ( Object o ) {
if ( this == o ) return 0; // If same object.
if ( o == null || getClass() != o.getClass() ) return 0;
LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
return this.getDateRange().getStart().compareTo( thatStart );
}

static public class StopDateComparator implements Comparator < Term > {

@Override
public int compare ( Term t1 , Term t2 ) {
return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
}
}

}


Try it.



public static void main ( String args ) {
Term t1 = new Term( LocalDate.of( 2018 , Month.JUNE , 23 ) , LocalDate.of( 2018 , Month.JULY , 23 ) , UUID.randomUUID() );
Term t2 = new Term( LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.DECEMBER , 23 ) , UUID.randomUUID() );
Term t3 = new Term( LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.APRIL , 23 ) , UUID.randomUUID() );
List < Term > terms = new ArrayList <>( List.of( t1 , t2 , t3 ) );
System.out.println( "Before natural sort: " + terms );
Collections.sort( terms );
System.out.println( "After natural sort: " + terms );
Collections.sort( terms , new Term.StopDateComparator() );
System.out.println( "After Comparator sort: " + terms );
}



Before natural sort: [Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }]



After natural sort: [Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }]



After Comparator sort: [Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }]




abuts



If your Term objects should run up against one another in succession, you can test for that using the LocalDateRange::abuts method.



The approach in comparing is Half-Open, where the beginning is inclusive while the ending is exclusive. So a year starts on the first of the year and runs up to, but does not include, the first of the following year. You show this in your examples in the Question.






share|improve this answer

































    0














    I assume the question is not just about sorting, but also about splitting overlapping intervals into smaller segments. You have to play a lot with Interval Arithmetic.



    With Java 8 you can start by encoding your 'terms' as a time Interval, which in itself is Comparable. The second part would be to split your intervals into multiple ones if the user specifies overlapping ones.



    class Interval implements Comparable<Interval> {
    private final LocalDateTime start;
    private final LocalDateTime end;

    public Interval(LocalDateTime start, LocalDateTime end) {
    this.start = start;
    this.end = end;
    }

    public int compareTo(Interval that) {
    return this.start.compareTo(that.start);
    }

    public boolean overlaps(Interval that) {
    return !this.isBefore(that) && !this.isAfter(that);
    }

    public boolean contains(Interval that) {
    return this.start.isBefore(that.start) && this.end.isAfter(that.end);
    }

    public boolean isBefore(Interval that) {
    return this.end.isBefore(that.start);
    }

    public boolean isAfter(Interval that) {
    return this.start.isAfter(that.end);
    }

    public Set<Interval> fragment(Interval that) {
    if (that.start.isBefore(this.start)) {
    return that.fragment(this);
    }

    Set<Interval> result = new HashSet<>();
    if (this.end.isBefore(that.start)) {
    result.add(this);
    result.add(that);
    result.add(new Interval(this.end, that.start));
    } else if ((this.end.isAfter(that.start) && this.end.isBefore(that.end)) {
    result.add(new Interval(this.start, that.start);
    result.add(new Interval(that.start, this.end);
    result.add(new Interval(this.end, that.end));
    } else if (this.end.isAfter(that.end)) {
    result.add(new Interval(this.start, that.start);
    result.add(new Interval(that);
    result.add(new Interval(that.end, this.end));
    }
    }
    }


    You can now keep them sorted, since Intervals are comparable by start date.
    Whenever the user enters a new Interval (term) you have to go through the list and checks whether it contains() the existent interval, or whether it comes before it, with isBefore() or isAfter(). If it overlaps() you have to be careful if to also check whether it overlaps with the next interval in the list.



    You can then call fragment() which will combine the 2 intervals together into smaller ones. You need to be careful to remove the previous ones. So maybe makes sense to just go through the list and check if they overlap or not. If you reach the end you can still use fragment() to combine two disjoint intervals.






    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53284130%2fhow-to-compare-instanced-datetime-objects%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      0














      Put every date in a new collection, sort it by the date, and then create new objects that consist neighbour dates from the collection.



      Try:



      public static void main(String args) {
      List<YourClass> list = new ArrayList<>();

      list.add(new YourClass(new Date(100000000), new Date(200000000)));
      list.add(new YourClass(new Date(150000000), new Date(250000000)));
      list.add(new YourClass(new Date(50000000), new Date(300000000)));

      System.out.println(list);

      List<Date> dates = new ArrayList<>();
      for (YourClass yc : list){
      if (!dates.contains(yc.beginning)) dates.add(yc.beginning);
      if (!dates.contains(yc.end)) dates.add(yc.end);
      }

      Collections.sort(dates);

      List<YourClass> list2 = new ArrayList<>();

      for (int i=0; i < dates.size() -1; i++){
      list2.add(new YourClass(dates.get(i), dates.get(i+1)));
      }

      System.out.println(list2);

      }

      public static class YourClass {
      Date beginning;
      Date end;

      public YourClass(Date beginning, Date end) {
      this.beginning = beginning;
      this.end = end;
      }

      @Override
      public String toString() {
      return "n" + beginning + " -> " + end ;
      }
      }





      share|improve this answer
























      • I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdated Date class.

        – Ole V.V.
        Nov 13 '18 at 19:20






      • 1





        Yes, its not best solution, just an illustration of algorithm working. LocalDate class is preferred for workig with date and implements Comparable as like a Date class.

        – Mark
        Nov 13 '18 at 20:01











      • This is doing exactly what I want it to do and half the code I had already. I only added the new Array and sorted it via collections. Thanks for this so far. But I fail to understand why this works. How does the .sort in collections know how I want to sort it exactly?

        – JB1989
        Nov 14 '18 at 7:34













      • Date class, LocalDate class, Integer class and more else classes implement Comparable interface. It means that inside the class discribed the rule how to compare two this class objects. And Sort method use this rule for sorting.

        – Mark
        Nov 14 '18 at 8:02
















      0














      Put every date in a new collection, sort it by the date, and then create new objects that consist neighbour dates from the collection.



      Try:



      public static void main(String args) {
      List<YourClass> list = new ArrayList<>();

      list.add(new YourClass(new Date(100000000), new Date(200000000)));
      list.add(new YourClass(new Date(150000000), new Date(250000000)));
      list.add(new YourClass(new Date(50000000), new Date(300000000)));

      System.out.println(list);

      List<Date> dates = new ArrayList<>();
      for (YourClass yc : list){
      if (!dates.contains(yc.beginning)) dates.add(yc.beginning);
      if (!dates.contains(yc.end)) dates.add(yc.end);
      }

      Collections.sort(dates);

      List<YourClass> list2 = new ArrayList<>();

      for (int i=0; i < dates.size() -1; i++){
      list2.add(new YourClass(dates.get(i), dates.get(i+1)));
      }

      System.out.println(list2);

      }

      public static class YourClass {
      Date beginning;
      Date end;

      public YourClass(Date beginning, Date end) {
      this.beginning = beginning;
      this.end = end;
      }

      @Override
      public String toString() {
      return "n" + beginning + " -> " + end ;
      }
      }





      share|improve this answer
























      • I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdated Date class.

        – Ole V.V.
        Nov 13 '18 at 19:20






      • 1





        Yes, its not best solution, just an illustration of algorithm working. LocalDate class is preferred for workig with date and implements Comparable as like a Date class.

        – Mark
        Nov 13 '18 at 20:01











      • This is doing exactly what I want it to do and half the code I had already. I only added the new Array and sorted it via collections. Thanks for this so far. But I fail to understand why this works. How does the .sort in collections know how I want to sort it exactly?

        – JB1989
        Nov 14 '18 at 7:34













      • Date class, LocalDate class, Integer class and more else classes implement Comparable interface. It means that inside the class discribed the rule how to compare two this class objects. And Sort method use this rule for sorting.

        – Mark
        Nov 14 '18 at 8:02














      0












      0








      0







      Put every date in a new collection, sort it by the date, and then create new objects that consist neighbour dates from the collection.



      Try:



      public static void main(String args) {
      List<YourClass> list = new ArrayList<>();

      list.add(new YourClass(new Date(100000000), new Date(200000000)));
      list.add(new YourClass(new Date(150000000), new Date(250000000)));
      list.add(new YourClass(new Date(50000000), new Date(300000000)));

      System.out.println(list);

      List<Date> dates = new ArrayList<>();
      for (YourClass yc : list){
      if (!dates.contains(yc.beginning)) dates.add(yc.beginning);
      if (!dates.contains(yc.end)) dates.add(yc.end);
      }

      Collections.sort(dates);

      List<YourClass> list2 = new ArrayList<>();

      for (int i=0; i < dates.size() -1; i++){
      list2.add(new YourClass(dates.get(i), dates.get(i+1)));
      }

      System.out.println(list2);

      }

      public static class YourClass {
      Date beginning;
      Date end;

      public YourClass(Date beginning, Date end) {
      this.beginning = beginning;
      this.end = end;
      }

      @Override
      public String toString() {
      return "n" + beginning + " -> " + end ;
      }
      }





      share|improve this answer













      Put every date in a new collection, sort it by the date, and then create new objects that consist neighbour dates from the collection.



      Try:



      public static void main(String args) {
      List<YourClass> list = new ArrayList<>();

      list.add(new YourClass(new Date(100000000), new Date(200000000)));
      list.add(new YourClass(new Date(150000000), new Date(250000000)));
      list.add(new YourClass(new Date(50000000), new Date(300000000)));

      System.out.println(list);

      List<Date> dates = new ArrayList<>();
      for (YourClass yc : list){
      if (!dates.contains(yc.beginning)) dates.add(yc.beginning);
      if (!dates.contains(yc.end)) dates.add(yc.end);
      }

      Collections.sort(dates);

      List<YourClass> list2 = new ArrayList<>();

      for (int i=0; i < dates.size() -1; i++){
      list2.add(new YourClass(dates.get(i), dates.get(i+1)));
      }

      System.out.println(list2);

      }

      public static class YourClass {
      Date beginning;
      Date end;

      public YourClass(Date beginning, Date end) {
      this.beginning = beginning;
      this.end = end;
      }

      @Override
      public String toString() {
      return "n" + beginning + " -> " + end ;
      }
      }






      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Nov 13 '18 at 16:04









      MarkMark

      2243




      2243













      • I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdated Date class.

        – Ole V.V.
        Nov 13 '18 at 19:20






      • 1





        Yes, its not best solution, just an illustration of algorithm working. LocalDate class is preferred for workig with date and implements Comparable as like a Date class.

        – Mark
        Nov 13 '18 at 20:01











      • This is doing exactly what I want it to do and half the code I had already. I only added the new Array and sorted it via collections. Thanks for this so far. But I fail to understand why this works. How does the .sort in collections know how I want to sort it exactly?

        – JB1989
        Nov 14 '18 at 7:34













      • Date class, LocalDate class, Integer class and more else classes implement Comparable interface. It means that inside the class discribed the rule how to compare two this class objects. And Sort method use this rule for sorting.

        – Mark
        Nov 14 '18 at 8:02



















      • I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdated Date class.

        – Ole V.V.
        Nov 13 '18 at 19:20






      • 1





        Yes, its not best solution, just an illustration of algorithm working. LocalDate class is preferred for workig with date and implements Comparable as like a Date class.

        – Mark
        Nov 13 '18 at 20:01











      • This is doing exactly what I want it to do and half the code I had already. I only added the new Array and sorted it via collections. Thanks for this so far. But I fail to understand why this works. How does the .sort in collections know how I want to sort it exactly?

        – JB1989
        Nov 14 '18 at 7:34













      • Date class, LocalDate class, Integer class and more else classes implement Comparable interface. It means that inside the class discribed the rule how to compare two this class objects. And Sort method use this rule for sorting.

        – Mark
        Nov 14 '18 at 8:02

















      I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdated Date class.

      – Ole V.V.
      Nov 13 '18 at 19:20





      I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdated Date class.

      – Ole V.V.
      Nov 13 '18 at 19:20




      1




      1





      Yes, its not best solution, just an illustration of algorithm working. LocalDate class is preferred for workig with date and implements Comparable as like a Date class.

      – Mark
      Nov 13 '18 at 20:01





      Yes, its not best solution, just an illustration of algorithm working. LocalDate class is preferred for workig with date and implements Comparable as like a Date class.

      – Mark
      Nov 13 '18 at 20:01













      This is doing exactly what I want it to do and half the code I had already. I only added the new Array and sorted it via collections. Thanks for this so far. But I fail to understand why this works. How does the .sort in collections know how I want to sort it exactly?

      – JB1989
      Nov 14 '18 at 7:34







      This is doing exactly what I want it to do and half the code I had already. I only added the new Array and sorted it via collections. Thanks for this so far. But I fail to understand why this works. How does the .sort in collections know how I want to sort it exactly?

      – JB1989
      Nov 14 '18 at 7:34















      Date class, LocalDate class, Integer class and more else classes implement Comparable interface. It means that inside the class discribed the rule how to compare two this class objects. And Sort method use this rule for sorting.

      – Mark
      Nov 14 '18 at 8:02





      Date class, LocalDate class, Integer class and more else classes implement Comparable interface. It means that inside the class discribed the rule how to compare two this class objects. And Sort method use this rule for sorting.

      – Mark
      Nov 14 '18 at 8:02













      1














      tl;dr




      What I want to do is to sort all DateTime beginning and all DateTime end by date.




      You can do one or the other but not both.



      To sort by start date (seems sensible in practice), implement compareTo method.



      return this.getDateRange().getStart().compareTo( thatStart );


      To sort by stop date (I do not see any sense in this), implement the Comparator interface.



      return 
      t1.getDateRange().getEnd().compareTo(
      t2.getDateRange().getEnd()
      )
      ;


      LocalDate



      As others noted, you should be using the modern java.time classes, never the terrible old Date/Calendar/SimpleDateFormat classes. For a date-only value, without time-of-day and without time zone, use LocalDate.



      LocalDateRange



      As the Answer by jbx discusses, you should represent your term’s start and stop dates as a pair. But do not write a class when one already exists. Use LocalDateRange class from the ThreeTen-Extra project. This project adds functionality to the java.time classes.



      Comparable



      On your Term class, implement Comparable interface to enable simple easy sorting. Add the method compareTo. The obvious approach there would be to compare the starting LocalDate of each Term object’s LocalDateRange object.



      The LocalDate class implements compareTo, no we don’ have to.



      @Override
      public int compareTo ( Object o ) {
      if ( this == o ) return 0;
      if ( o == null || getClass() != o.getClass() ) return 0;
      LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
      return this.getDateRange().getStart().compareTo( thatStart );
      }


      See the Java Tutorial on object-ordering.



      Sort by stop date



      Your Question is not clear, but you seem to be asking to alternatively sort by the ending date. I cannot imagine how this is useful in practical terms. But anyways, the solution is to sort by providing an implementation of the Comparator interface.



          @Override
      public int compare ( Term t1 , Term t2 ) {
      return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
      }


      Example class



      Here is an example Term class. May not be production-quality code, but should get you going in the right direction.



      package com.basilbourque.example;

      import org.threeten.extra.LocalDateRange;

      import java.time.LocalDate;
      import java.time.Month;
      import java.util.*;

      public class Term implements Comparable {
      private UUID id;
      private LocalDateRange dateRange;

      // Constructor
      public Term ( LocalDate start , LocalDate stop , UUID id ) {
      Objects.requireNonNull( start ); // TODO: Add more such checks for all arguments.
      if ( start.getYear() < 2015 ) { // TODO: Add more such checks for too far into the past or future, for both start and for stop.
      throw new IllegalArgumentException( "Year of start date is too far in the past. Message # afcd30a0-b639-4ccf-b064-18cc2ea8587b." );
      }
      this.id = id;
      this.dateRange = LocalDateRange.of( start , stop );
      }

      // Alternative constructor.
      public Term ( LocalDateRange dateRange , UUID id ) {
      this( dateRange.getStart() , dateRange.getEnd() , id );
      }



      // --------| Object |-------------------------
      @Override
      public String toString ( ) {
      return "Term{ " +
      "id=" + id +
      " | dateRange=" + dateRange +
      " }";
      }

      public UUID getId ( ) {
      return id;
      }

      public LocalDateRange getDateRange ( ) {
      return dateRange;
      }

      @Override
      public boolean equals ( Object o ) {
      if ( this == o ) return true;
      if ( o == null || getClass() != o.getClass() ) return false;
      Term term = ( Term ) o;
      return this.getId().equals( term.getId() );
      }

      @Override
      public int hashCode ( ) {
      return Objects.hash( this.getId() );
      }

      @Override
      public int compareTo ( Object o ) {
      if ( this == o ) return 0; // If same object.
      if ( o == null || getClass() != o.getClass() ) return 0;
      LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
      return this.getDateRange().getStart().compareTo( thatStart );
      }

      static public class StopDateComparator implements Comparator < Term > {

      @Override
      public int compare ( Term t1 , Term t2 ) {
      return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
      }
      }

      }


      Try it.



      public static void main ( String args ) {
      Term t1 = new Term( LocalDate.of( 2018 , Month.JUNE , 23 ) , LocalDate.of( 2018 , Month.JULY , 23 ) , UUID.randomUUID() );
      Term t2 = new Term( LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.DECEMBER , 23 ) , UUID.randomUUID() );
      Term t3 = new Term( LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.APRIL , 23 ) , UUID.randomUUID() );
      List < Term > terms = new ArrayList <>( List.of( t1 , t2 , t3 ) );
      System.out.println( "Before natural sort: " + terms );
      Collections.sort( terms );
      System.out.println( "After natural sort: " + terms );
      Collections.sort( terms , new Term.StopDateComparator() );
      System.out.println( "After Comparator sort: " + terms );
      }



      Before natural sort: [Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }]



      After natural sort: [Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }]



      After Comparator sort: [Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }]




      abuts



      If your Term objects should run up against one another in succession, you can test for that using the LocalDateRange::abuts method.



      The approach in comparing is Half-Open, where the beginning is inclusive while the ending is exclusive. So a year starts on the first of the year and runs up to, but does not include, the first of the following year. You show this in your examples in the Question.






      share|improve this answer






























        1














        tl;dr




        What I want to do is to sort all DateTime beginning and all DateTime end by date.




        You can do one or the other but not both.



        To sort by start date (seems sensible in practice), implement compareTo method.



        return this.getDateRange().getStart().compareTo( thatStart );


        To sort by stop date (I do not see any sense in this), implement the Comparator interface.



        return 
        t1.getDateRange().getEnd().compareTo(
        t2.getDateRange().getEnd()
        )
        ;


        LocalDate



        As others noted, you should be using the modern java.time classes, never the terrible old Date/Calendar/SimpleDateFormat classes. For a date-only value, without time-of-day and without time zone, use LocalDate.



        LocalDateRange



        As the Answer by jbx discusses, you should represent your term’s start and stop dates as a pair. But do not write a class when one already exists. Use LocalDateRange class from the ThreeTen-Extra project. This project adds functionality to the java.time classes.



        Comparable



        On your Term class, implement Comparable interface to enable simple easy sorting. Add the method compareTo. The obvious approach there would be to compare the starting LocalDate of each Term object’s LocalDateRange object.



        The LocalDate class implements compareTo, no we don’ have to.



        @Override
        public int compareTo ( Object o ) {
        if ( this == o ) return 0;
        if ( o == null || getClass() != o.getClass() ) return 0;
        LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
        return this.getDateRange().getStart().compareTo( thatStart );
        }


        See the Java Tutorial on object-ordering.



        Sort by stop date



        Your Question is not clear, but you seem to be asking to alternatively sort by the ending date. I cannot imagine how this is useful in practical terms. But anyways, the solution is to sort by providing an implementation of the Comparator interface.



            @Override
        public int compare ( Term t1 , Term t2 ) {
        return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
        }


        Example class



        Here is an example Term class. May not be production-quality code, but should get you going in the right direction.



        package com.basilbourque.example;

        import org.threeten.extra.LocalDateRange;

        import java.time.LocalDate;
        import java.time.Month;
        import java.util.*;

        public class Term implements Comparable {
        private UUID id;
        private LocalDateRange dateRange;

        // Constructor
        public Term ( LocalDate start , LocalDate stop , UUID id ) {
        Objects.requireNonNull( start ); // TODO: Add more such checks for all arguments.
        if ( start.getYear() < 2015 ) { // TODO: Add more such checks for too far into the past or future, for both start and for stop.
        throw new IllegalArgumentException( "Year of start date is too far in the past. Message # afcd30a0-b639-4ccf-b064-18cc2ea8587b." );
        }
        this.id = id;
        this.dateRange = LocalDateRange.of( start , stop );
        }

        // Alternative constructor.
        public Term ( LocalDateRange dateRange , UUID id ) {
        this( dateRange.getStart() , dateRange.getEnd() , id );
        }



        // --------| Object |-------------------------
        @Override
        public String toString ( ) {
        return "Term{ " +
        "id=" + id +
        " | dateRange=" + dateRange +
        " }";
        }

        public UUID getId ( ) {
        return id;
        }

        public LocalDateRange getDateRange ( ) {
        return dateRange;
        }

        @Override
        public boolean equals ( Object o ) {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        Term term = ( Term ) o;
        return this.getId().equals( term.getId() );
        }

        @Override
        public int hashCode ( ) {
        return Objects.hash( this.getId() );
        }

        @Override
        public int compareTo ( Object o ) {
        if ( this == o ) return 0; // If same object.
        if ( o == null || getClass() != o.getClass() ) return 0;
        LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
        return this.getDateRange().getStart().compareTo( thatStart );
        }

        static public class StopDateComparator implements Comparator < Term > {

        @Override
        public int compare ( Term t1 , Term t2 ) {
        return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
        }
        }

        }


        Try it.



        public static void main ( String args ) {
        Term t1 = new Term( LocalDate.of( 2018 , Month.JUNE , 23 ) , LocalDate.of( 2018 , Month.JULY , 23 ) , UUID.randomUUID() );
        Term t2 = new Term( LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.DECEMBER , 23 ) , UUID.randomUUID() );
        Term t3 = new Term( LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.APRIL , 23 ) , UUID.randomUUID() );
        List < Term > terms = new ArrayList <>( List.of( t1 , t2 , t3 ) );
        System.out.println( "Before natural sort: " + terms );
        Collections.sort( terms );
        System.out.println( "After natural sort: " + terms );
        Collections.sort( terms , new Term.StopDateComparator() );
        System.out.println( "After Comparator sort: " + terms );
        }



        Before natural sort: [Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }]



        After natural sort: [Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }]



        After Comparator sort: [Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }]




        abuts



        If your Term objects should run up against one another in succession, you can test for that using the LocalDateRange::abuts method.



        The approach in comparing is Half-Open, where the beginning is inclusive while the ending is exclusive. So a year starts on the first of the year and runs up to, but does not include, the first of the following year. You show this in your examples in the Question.






        share|improve this answer




























          1












          1








          1







          tl;dr




          What I want to do is to sort all DateTime beginning and all DateTime end by date.




          You can do one or the other but not both.



          To sort by start date (seems sensible in practice), implement compareTo method.



          return this.getDateRange().getStart().compareTo( thatStart );


          To sort by stop date (I do not see any sense in this), implement the Comparator interface.



          return 
          t1.getDateRange().getEnd().compareTo(
          t2.getDateRange().getEnd()
          )
          ;


          LocalDate



          As others noted, you should be using the modern java.time classes, never the terrible old Date/Calendar/SimpleDateFormat classes. For a date-only value, without time-of-day and without time zone, use LocalDate.



          LocalDateRange



          As the Answer by jbx discusses, you should represent your term’s start and stop dates as a pair. But do not write a class when one already exists. Use LocalDateRange class from the ThreeTen-Extra project. This project adds functionality to the java.time classes.



          Comparable



          On your Term class, implement Comparable interface to enable simple easy sorting. Add the method compareTo. The obvious approach there would be to compare the starting LocalDate of each Term object’s LocalDateRange object.



          The LocalDate class implements compareTo, no we don’ have to.



          @Override
          public int compareTo ( Object o ) {
          if ( this == o ) return 0;
          if ( o == null || getClass() != o.getClass() ) return 0;
          LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
          return this.getDateRange().getStart().compareTo( thatStart );
          }


          See the Java Tutorial on object-ordering.



          Sort by stop date



          Your Question is not clear, but you seem to be asking to alternatively sort by the ending date. I cannot imagine how this is useful in practical terms. But anyways, the solution is to sort by providing an implementation of the Comparator interface.



              @Override
          public int compare ( Term t1 , Term t2 ) {
          return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
          }


          Example class



          Here is an example Term class. May not be production-quality code, but should get you going in the right direction.



          package com.basilbourque.example;

          import org.threeten.extra.LocalDateRange;

          import java.time.LocalDate;
          import java.time.Month;
          import java.util.*;

          public class Term implements Comparable {
          private UUID id;
          private LocalDateRange dateRange;

          // Constructor
          public Term ( LocalDate start , LocalDate stop , UUID id ) {
          Objects.requireNonNull( start ); // TODO: Add more such checks for all arguments.
          if ( start.getYear() < 2015 ) { // TODO: Add more such checks for too far into the past or future, for both start and for stop.
          throw new IllegalArgumentException( "Year of start date is too far in the past. Message # afcd30a0-b639-4ccf-b064-18cc2ea8587b." );
          }
          this.id = id;
          this.dateRange = LocalDateRange.of( start , stop );
          }

          // Alternative constructor.
          public Term ( LocalDateRange dateRange , UUID id ) {
          this( dateRange.getStart() , dateRange.getEnd() , id );
          }



          // --------| Object |-------------------------
          @Override
          public String toString ( ) {
          return "Term{ " +
          "id=" + id +
          " | dateRange=" + dateRange +
          " }";
          }

          public UUID getId ( ) {
          return id;
          }

          public LocalDateRange getDateRange ( ) {
          return dateRange;
          }

          @Override
          public boolean equals ( Object o ) {
          if ( this == o ) return true;
          if ( o == null || getClass() != o.getClass() ) return false;
          Term term = ( Term ) o;
          return this.getId().equals( term.getId() );
          }

          @Override
          public int hashCode ( ) {
          return Objects.hash( this.getId() );
          }

          @Override
          public int compareTo ( Object o ) {
          if ( this == o ) return 0; // If same object.
          if ( o == null || getClass() != o.getClass() ) return 0;
          LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
          return this.getDateRange().getStart().compareTo( thatStart );
          }

          static public class StopDateComparator implements Comparator < Term > {

          @Override
          public int compare ( Term t1 , Term t2 ) {
          return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
          }
          }

          }


          Try it.



          public static void main ( String args ) {
          Term t1 = new Term( LocalDate.of( 2018 , Month.JUNE , 23 ) , LocalDate.of( 2018 , Month.JULY , 23 ) , UUID.randomUUID() );
          Term t2 = new Term( LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.DECEMBER , 23 ) , UUID.randomUUID() );
          Term t3 = new Term( LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.APRIL , 23 ) , UUID.randomUUID() );
          List < Term > terms = new ArrayList <>( List.of( t1 , t2 , t3 ) );
          System.out.println( "Before natural sort: " + terms );
          Collections.sort( terms );
          System.out.println( "After natural sort: " + terms );
          Collections.sort( terms , new Term.StopDateComparator() );
          System.out.println( "After Comparator sort: " + terms );
          }



          Before natural sort: [Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }]



          After natural sort: [Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }]



          After Comparator sort: [Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }]




          abuts



          If your Term objects should run up against one another in succession, you can test for that using the LocalDateRange::abuts method.



          The approach in comparing is Half-Open, where the beginning is inclusive while the ending is exclusive. So a year starts on the first of the year and runs up to, but does not include, the first of the following year. You show this in your examples in the Question.






          share|improve this answer















          tl;dr




          What I want to do is to sort all DateTime beginning and all DateTime end by date.




          You can do one or the other but not both.



          To sort by start date (seems sensible in practice), implement compareTo method.



          return this.getDateRange().getStart().compareTo( thatStart );


          To sort by stop date (I do not see any sense in this), implement the Comparator interface.



          return 
          t1.getDateRange().getEnd().compareTo(
          t2.getDateRange().getEnd()
          )
          ;


          LocalDate



          As others noted, you should be using the modern java.time classes, never the terrible old Date/Calendar/SimpleDateFormat classes. For a date-only value, without time-of-day and without time zone, use LocalDate.



          LocalDateRange



          As the Answer by jbx discusses, you should represent your term’s start and stop dates as a pair. But do not write a class when one already exists. Use LocalDateRange class from the ThreeTen-Extra project. This project adds functionality to the java.time classes.



          Comparable



          On your Term class, implement Comparable interface to enable simple easy sorting. Add the method compareTo. The obvious approach there would be to compare the starting LocalDate of each Term object’s LocalDateRange object.



          The LocalDate class implements compareTo, no we don’ have to.



          @Override
          public int compareTo ( Object o ) {
          if ( this == o ) return 0;
          if ( o == null || getClass() != o.getClass() ) return 0;
          LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
          return this.getDateRange().getStart().compareTo( thatStart );
          }


          See the Java Tutorial on object-ordering.



          Sort by stop date



          Your Question is not clear, but you seem to be asking to alternatively sort by the ending date. I cannot imagine how this is useful in practical terms. But anyways, the solution is to sort by providing an implementation of the Comparator interface.



              @Override
          public int compare ( Term t1 , Term t2 ) {
          return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
          }


          Example class



          Here is an example Term class. May not be production-quality code, but should get you going in the right direction.



          package com.basilbourque.example;

          import org.threeten.extra.LocalDateRange;

          import java.time.LocalDate;
          import java.time.Month;
          import java.util.*;

          public class Term implements Comparable {
          private UUID id;
          private LocalDateRange dateRange;

          // Constructor
          public Term ( LocalDate start , LocalDate stop , UUID id ) {
          Objects.requireNonNull( start ); // TODO: Add more such checks for all arguments.
          if ( start.getYear() < 2015 ) { // TODO: Add more such checks for too far into the past or future, for both start and for stop.
          throw new IllegalArgumentException( "Year of start date is too far in the past. Message # afcd30a0-b639-4ccf-b064-18cc2ea8587b." );
          }
          this.id = id;
          this.dateRange = LocalDateRange.of( start , stop );
          }

          // Alternative constructor.
          public Term ( LocalDateRange dateRange , UUID id ) {
          this( dateRange.getStart() , dateRange.getEnd() , id );
          }



          // --------| Object |-------------------------
          @Override
          public String toString ( ) {
          return "Term{ " +
          "id=" + id +
          " | dateRange=" + dateRange +
          " }";
          }

          public UUID getId ( ) {
          return id;
          }

          public LocalDateRange getDateRange ( ) {
          return dateRange;
          }

          @Override
          public boolean equals ( Object o ) {
          if ( this == o ) return true;
          if ( o == null || getClass() != o.getClass() ) return false;
          Term term = ( Term ) o;
          return this.getId().equals( term.getId() );
          }

          @Override
          public int hashCode ( ) {
          return Objects.hash( this.getId() );
          }

          @Override
          public int compareTo ( Object o ) {
          if ( this == o ) return 0; // If same object.
          if ( o == null || getClass() != o.getClass() ) return 0;
          LocalDate thatStart = ( ( Term ) o ).getDateRange().getStart();
          return this.getDateRange().getStart().compareTo( thatStart );
          }

          static public class StopDateComparator implements Comparator < Term > {

          @Override
          public int compare ( Term t1 , Term t2 ) {
          return t1.getDateRange().getEnd().compareTo( t2.getDateRange().getEnd() );
          }
          }

          }


          Try it.



          public static void main ( String args ) {
          Term t1 = new Term( LocalDate.of( 2018 , Month.JUNE , 23 ) , LocalDate.of( 2018 , Month.JULY , 23 ) , UUID.randomUUID() );
          Term t2 = new Term( LocalDate.of( 2018 , Month.JANUARY , 23 ) , LocalDate.of( 2018 , Month.DECEMBER , 23 ) , UUID.randomUUID() );
          Term t3 = new Term( LocalDate.of( 2018 , Month.MARCH , 23 ) , LocalDate.of( 2018 , Month.APRIL , 23 ) , UUID.randomUUID() );
          List < Term > terms = new ArrayList <>( List.of( t1 , t2 , t3 ) );
          System.out.println( "Before natural sort: " + terms );
          Collections.sort( terms );
          System.out.println( "After natural sort: " + terms );
          Collections.sort( terms , new Term.StopDateComparator() );
          System.out.println( "After Comparator sort: " + terms );
          }



          Before natural sort: [Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }]



          After natural sort: [Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }, Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }]



          After Comparator sort: [Term{ id=c49f79e1-11cd-4865-aa46-8fbf3c85dbfd | dateRange=2018-03-23/2018-04-23 }, Term{ id=27c0b9e6-076f-4ded-9bbd-bf1a2c7914bc | dateRange=2018-06-23/2018-07-23 }, Term{ id=792bf365-eca4-460b-afad-c5cf62cf9a29 | dateRange=2018-01-23/2018-12-23 }]




          abuts



          If your Term objects should run up against one another in succession, you can test for that using the LocalDateRange::abuts method.



          The approach in comparing is Half-Open, where the beginning is inclusive while the ending is exclusive. So a year starts on the first of the year and runs up to, but does not include, the first of the following year. You show this in your examples in the Question.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 13 '18 at 21:20

























          answered Nov 13 '18 at 18:50









          Basil BourqueBasil Bourque

          107k25369532




          107k25369532























              0














              I assume the question is not just about sorting, but also about splitting overlapping intervals into smaller segments. You have to play a lot with Interval Arithmetic.



              With Java 8 you can start by encoding your 'terms' as a time Interval, which in itself is Comparable. The second part would be to split your intervals into multiple ones if the user specifies overlapping ones.



              class Interval implements Comparable<Interval> {
              private final LocalDateTime start;
              private final LocalDateTime end;

              public Interval(LocalDateTime start, LocalDateTime end) {
              this.start = start;
              this.end = end;
              }

              public int compareTo(Interval that) {
              return this.start.compareTo(that.start);
              }

              public boolean overlaps(Interval that) {
              return !this.isBefore(that) && !this.isAfter(that);
              }

              public boolean contains(Interval that) {
              return this.start.isBefore(that.start) && this.end.isAfter(that.end);
              }

              public boolean isBefore(Interval that) {
              return this.end.isBefore(that.start);
              }

              public boolean isAfter(Interval that) {
              return this.start.isAfter(that.end);
              }

              public Set<Interval> fragment(Interval that) {
              if (that.start.isBefore(this.start)) {
              return that.fragment(this);
              }

              Set<Interval> result = new HashSet<>();
              if (this.end.isBefore(that.start)) {
              result.add(this);
              result.add(that);
              result.add(new Interval(this.end, that.start));
              } else if ((this.end.isAfter(that.start) && this.end.isBefore(that.end)) {
              result.add(new Interval(this.start, that.start);
              result.add(new Interval(that.start, this.end);
              result.add(new Interval(this.end, that.end));
              } else if (this.end.isAfter(that.end)) {
              result.add(new Interval(this.start, that.start);
              result.add(new Interval(that);
              result.add(new Interval(that.end, this.end));
              }
              }
              }


              You can now keep them sorted, since Intervals are comparable by start date.
              Whenever the user enters a new Interval (term) you have to go through the list and checks whether it contains() the existent interval, or whether it comes before it, with isBefore() or isAfter(). If it overlaps() you have to be careful if to also check whether it overlaps with the next interval in the list.



              You can then call fragment() which will combine the 2 intervals together into smaller ones. You need to be careful to remove the previous ones. So maybe makes sense to just go through the list and check if they overlap or not. If you reach the end you can still use fragment() to combine two disjoint intervals.






              share|improve this answer




























                0














                I assume the question is not just about sorting, but also about splitting overlapping intervals into smaller segments. You have to play a lot with Interval Arithmetic.



                With Java 8 you can start by encoding your 'terms' as a time Interval, which in itself is Comparable. The second part would be to split your intervals into multiple ones if the user specifies overlapping ones.



                class Interval implements Comparable<Interval> {
                private final LocalDateTime start;
                private final LocalDateTime end;

                public Interval(LocalDateTime start, LocalDateTime end) {
                this.start = start;
                this.end = end;
                }

                public int compareTo(Interval that) {
                return this.start.compareTo(that.start);
                }

                public boolean overlaps(Interval that) {
                return !this.isBefore(that) && !this.isAfter(that);
                }

                public boolean contains(Interval that) {
                return this.start.isBefore(that.start) && this.end.isAfter(that.end);
                }

                public boolean isBefore(Interval that) {
                return this.end.isBefore(that.start);
                }

                public boolean isAfter(Interval that) {
                return this.start.isAfter(that.end);
                }

                public Set<Interval> fragment(Interval that) {
                if (that.start.isBefore(this.start)) {
                return that.fragment(this);
                }

                Set<Interval> result = new HashSet<>();
                if (this.end.isBefore(that.start)) {
                result.add(this);
                result.add(that);
                result.add(new Interval(this.end, that.start));
                } else if ((this.end.isAfter(that.start) && this.end.isBefore(that.end)) {
                result.add(new Interval(this.start, that.start);
                result.add(new Interval(that.start, this.end);
                result.add(new Interval(this.end, that.end));
                } else if (this.end.isAfter(that.end)) {
                result.add(new Interval(this.start, that.start);
                result.add(new Interval(that);
                result.add(new Interval(that.end, this.end));
                }
                }
                }


                You can now keep them sorted, since Intervals are comparable by start date.
                Whenever the user enters a new Interval (term) you have to go through the list and checks whether it contains() the existent interval, or whether it comes before it, with isBefore() or isAfter(). If it overlaps() you have to be careful if to also check whether it overlaps with the next interval in the list.



                You can then call fragment() which will combine the 2 intervals together into smaller ones. You need to be careful to remove the previous ones. So maybe makes sense to just go through the list and check if they overlap or not. If you reach the end you can still use fragment() to combine two disjoint intervals.






                share|improve this answer


























                  0












                  0








                  0







                  I assume the question is not just about sorting, but also about splitting overlapping intervals into smaller segments. You have to play a lot with Interval Arithmetic.



                  With Java 8 you can start by encoding your 'terms' as a time Interval, which in itself is Comparable. The second part would be to split your intervals into multiple ones if the user specifies overlapping ones.



                  class Interval implements Comparable<Interval> {
                  private final LocalDateTime start;
                  private final LocalDateTime end;

                  public Interval(LocalDateTime start, LocalDateTime end) {
                  this.start = start;
                  this.end = end;
                  }

                  public int compareTo(Interval that) {
                  return this.start.compareTo(that.start);
                  }

                  public boolean overlaps(Interval that) {
                  return !this.isBefore(that) && !this.isAfter(that);
                  }

                  public boolean contains(Interval that) {
                  return this.start.isBefore(that.start) && this.end.isAfter(that.end);
                  }

                  public boolean isBefore(Interval that) {
                  return this.end.isBefore(that.start);
                  }

                  public boolean isAfter(Interval that) {
                  return this.start.isAfter(that.end);
                  }

                  public Set<Interval> fragment(Interval that) {
                  if (that.start.isBefore(this.start)) {
                  return that.fragment(this);
                  }

                  Set<Interval> result = new HashSet<>();
                  if (this.end.isBefore(that.start)) {
                  result.add(this);
                  result.add(that);
                  result.add(new Interval(this.end, that.start));
                  } else if ((this.end.isAfter(that.start) && this.end.isBefore(that.end)) {
                  result.add(new Interval(this.start, that.start);
                  result.add(new Interval(that.start, this.end);
                  result.add(new Interval(this.end, that.end));
                  } else if (this.end.isAfter(that.end)) {
                  result.add(new Interval(this.start, that.start);
                  result.add(new Interval(that);
                  result.add(new Interval(that.end, this.end));
                  }
                  }
                  }


                  You can now keep them sorted, since Intervals are comparable by start date.
                  Whenever the user enters a new Interval (term) you have to go through the list and checks whether it contains() the existent interval, or whether it comes before it, with isBefore() or isAfter(). If it overlaps() you have to be careful if to also check whether it overlaps with the next interval in the list.



                  You can then call fragment() which will combine the 2 intervals together into smaller ones. You need to be careful to remove the previous ones. So maybe makes sense to just go through the list and check if they overlap or not. If you reach the end you can still use fragment() to combine two disjoint intervals.






                  share|improve this answer













                  I assume the question is not just about sorting, but also about splitting overlapping intervals into smaller segments. You have to play a lot with Interval Arithmetic.



                  With Java 8 you can start by encoding your 'terms' as a time Interval, which in itself is Comparable. The second part would be to split your intervals into multiple ones if the user specifies overlapping ones.



                  class Interval implements Comparable<Interval> {
                  private final LocalDateTime start;
                  private final LocalDateTime end;

                  public Interval(LocalDateTime start, LocalDateTime end) {
                  this.start = start;
                  this.end = end;
                  }

                  public int compareTo(Interval that) {
                  return this.start.compareTo(that.start);
                  }

                  public boolean overlaps(Interval that) {
                  return !this.isBefore(that) && !this.isAfter(that);
                  }

                  public boolean contains(Interval that) {
                  return this.start.isBefore(that.start) && this.end.isAfter(that.end);
                  }

                  public boolean isBefore(Interval that) {
                  return this.end.isBefore(that.start);
                  }

                  public boolean isAfter(Interval that) {
                  return this.start.isAfter(that.end);
                  }

                  public Set<Interval> fragment(Interval that) {
                  if (that.start.isBefore(this.start)) {
                  return that.fragment(this);
                  }

                  Set<Interval> result = new HashSet<>();
                  if (this.end.isBefore(that.start)) {
                  result.add(this);
                  result.add(that);
                  result.add(new Interval(this.end, that.start));
                  } else if ((this.end.isAfter(that.start) && this.end.isBefore(that.end)) {
                  result.add(new Interval(this.start, that.start);
                  result.add(new Interval(that.start, this.end);
                  result.add(new Interval(this.end, that.end));
                  } else if (this.end.isAfter(that.end)) {
                  result.add(new Interval(this.start, that.start);
                  result.add(new Interval(that);
                  result.add(new Interval(that.end, this.end));
                  }
                  }
                  }


                  You can now keep them sorted, since Intervals are comparable by start date.
                  Whenever the user enters a new Interval (term) you have to go through the list and checks whether it contains() the existent interval, or whether it comes before it, with isBefore() or isAfter(). If it overlaps() you have to be careful if to also check whether it overlaps with the next interval in the list.



                  You can then call fragment() which will combine the 2 intervals together into smaller ones. You need to be careful to remove the previous ones. So maybe makes sense to just go through the list and check if they overlap or not. If you reach the end you can still use fragment() to combine two disjoint intervals.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 13 '18 at 16:09









                  jbxjbx

                  10.9k1057111




                  10.9k1057111






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53284130%2fhow-to-compare-instanced-datetime-objects%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Xamarin.iOS Cant Deploy on Iphone

                      Glorious Revolution

                      Dulmage-Mendelsohn matrix decomposition in Python