How to compare instanced DateTime objects?
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
|
show 3 more comments
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
Have a look atLocalDateTime
which implementsComparable
and has many useful features. Your question looks like you also want to knowLocalDate
, 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
|
show 3 more comments
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
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
java datetime
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 atLocalDateTime
which implementsComparable
and has many useful features. Your question looks like you also want to knowLocalDate
, 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
|
show 3 more comments
Have a look atLocalDateTime
which implementsComparable
and has many useful features. Your question looks like you also want to knowLocalDate
, 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
|
show 3 more comments
3 Answers
3
active
oldest
votes
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 ;
}
}
I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdatedDate
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
add a comment |
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.
add a comment |
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 Interval
s 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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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 ;
}
}
I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdatedDate
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
add a comment |
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 ;
}
}
I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdatedDate
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
add a comment |
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 ;
}
}
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 ;
}
}
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 outdatedDate
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
add a comment |
I believe your algorithm is right, but you shouldn’t use the poorly designed and long outdatedDate
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
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
edited Nov 13 '18 at 21:20
answered Nov 13 '18 at 18:50
Basil BourqueBasil Bourque
107k25369532
107k25369532
add a comment |
add a comment |
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 Interval
s 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.
add a comment |
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 Interval
s 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.
add a comment |
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 Interval
s 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.
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 Interval
s 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.
answered Nov 13 '18 at 16:09
jbxjbx
10.9k1057111
10.9k1057111
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
Have a look at
LocalDateTime
which implementsComparable
and has many useful features. Your question looks like you also want to knowLocalDate
, 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