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.