Comparing date with next object date in Arraylist not working as expected
I've a list of records, where each record has date objects inside it. I'm checking that the first record should have previous dates than the second, and second record dates should be less than 3rd record and so on.. Here is my code..
for(int i = 0; i < machines.size(); i++)
for(int j = i + 1; j < machines.size(); j++)
(machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
* machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()) >= 0))
throw new Exception("Dates are not as per criteria..");
My dates that are coming from the database is:
STRT_DT END_DT
---------- ----------
2014-01-01 2014-12-31
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2016-12-31
2017-01-01 2017-12-31
2018-01-01 2018-02-01
Am I missing anything? Any help would be greatly appreciated..
java date
|
show 3 more comments
I've a list of records, where each record has date objects inside it. I'm checking that the first record should have previous dates than the second, and second record dates should be less than 3rd record and so on.. Here is my code..
for(int i = 0; i < machines.size(); i++)
for(int j = i + 1; j < machines.size(); j++)
(machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
* machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()) >= 0))
throw new Exception("Dates are not as per criteria..");
My dates that are coming from the database is:
STRT_DT END_DT
---------- ----------
2014-01-01 2014-12-31
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2016-12-31
2017-01-01 2017-12-31
2018-01-01 2018-02-01
Am I missing anything? Any help would be greatly appreciated..
java date
1
Cannot understand why your if statement has the same condition ORed twice?
– robot_alien
Nov 14 '18 at 10:25
i * i > 0
, even ifi = -1
.
– 孙兴斌
Nov 14 '18 at 10:26
Because my first record i would be checking with second record j
– Syed
Nov 14 '18 at 10:27
Is it enough that start dates come in the right order? Or do you need to check for overlaps in time too? I mean where one end date would come after the following start date.
– Ole V.V.
Nov 14 '18 at 11:39
Since you have anArrayList
you could also use alistIterator()
to get compare thenext()
and theprevious()
date-pairs.
– LuCio
Nov 14 '18 at 11:47
|
show 3 more comments
I've a list of records, where each record has date objects inside it. I'm checking that the first record should have previous dates than the second, and second record dates should be less than 3rd record and so on.. Here is my code..
for(int i = 0; i < machines.size(); i++)
for(int j = i + 1; j < machines.size(); j++)
(machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
* machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()) >= 0))
throw new Exception("Dates are not as per criteria..");
My dates that are coming from the database is:
STRT_DT END_DT
---------- ----------
2014-01-01 2014-12-31
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2016-12-31
2017-01-01 2017-12-31
2018-01-01 2018-02-01
Am I missing anything? Any help would be greatly appreciated..
java date
I've a list of records, where each record has date objects inside it. I'm checking that the first record should have previous dates than the second, and second record dates should be less than 3rd record and so on.. Here is my code..
for(int i = 0; i < machines.size(); i++)
for(int j = i + 1; j < machines.size(); j++)
(machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
* machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()) >= 0))
throw new Exception("Dates are not as per criteria..");
My dates that are coming from the database is:
STRT_DT END_DT
---------- ----------
2014-01-01 2014-12-31
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2016-12-31
2017-01-01 2017-12-31
2018-01-01 2018-02-01
Am I missing anything? Any help would be greatly appreciated..
java date
java date
edited Nov 14 '18 at 22:51
Basil Bourque
111k27378542
111k27378542
asked Nov 14 '18 at 10:17
SyedSyed
83072048
83072048
1
Cannot understand why your if statement has the same condition ORed twice?
– robot_alien
Nov 14 '18 at 10:25
i * i > 0
, even ifi = -1
.
– 孙兴斌
Nov 14 '18 at 10:26
Because my first record i would be checking with second record j
– Syed
Nov 14 '18 at 10:27
Is it enough that start dates come in the right order? Or do you need to check for overlaps in time too? I mean where one end date would come after the following start date.
– Ole V.V.
Nov 14 '18 at 11:39
Since you have anArrayList
you could also use alistIterator()
to get compare thenext()
and theprevious()
date-pairs.
– LuCio
Nov 14 '18 at 11:47
|
show 3 more comments
1
Cannot understand why your if statement has the same condition ORed twice?
– robot_alien
Nov 14 '18 at 10:25
i * i > 0
, even ifi = -1
.
– 孙兴斌
Nov 14 '18 at 10:26
Because my first record i would be checking with second record j
– Syed
Nov 14 '18 at 10:27
Is it enough that start dates come in the right order? Or do you need to check for overlaps in time too? I mean where one end date would come after the following start date.
– Ole V.V.
Nov 14 '18 at 11:39
Since you have anArrayList
you could also use alistIterator()
to get compare thenext()
and theprevious()
date-pairs.
– LuCio
Nov 14 '18 at 11:47
1
1
Cannot understand why your if statement has the same condition ORed twice?
– robot_alien
Nov 14 '18 at 10:25
Cannot understand why your if statement has the same condition ORed twice?
– robot_alien
Nov 14 '18 at 10:25
i * i > 0
, even if i = -1
.– 孙兴斌
Nov 14 '18 at 10:26
i * i > 0
, even if i = -1
.– 孙兴斌
Nov 14 '18 at 10:26
Because my first record i would be checking with second record j
– Syed
Nov 14 '18 at 10:27
Because my first record i would be checking with second record j
– Syed
Nov 14 '18 at 10:27
Is it enough that start dates come in the right order? Or do you need to check for overlaps in time too? I mean where one end date would come after the following start date.
– Ole V.V.
Nov 14 '18 at 11:39
Is it enough that start dates come in the right order? Or do you need to check for overlaps in time too? I mean where one end date would come after the following start date.
– Ole V.V.
Nov 14 '18 at 11:39
Since you have an
ArrayList
you could also use a listIterator()
to get compare the next()
and the previous()
date-pairs.– LuCio
Nov 14 '18 at 11:47
Since you have an
ArrayList
you could also use a listIterator()
to get compare the next()
and the previous()
date-pairs.– LuCio
Nov 14 '18 at 11:47
|
show 3 more comments
3 Answers
3
active
oldest
votes
You’re over-complicating it. It’s enough to check pairwise entries since if a < b are in the right order and b < c are in the right order, then you already know that a < c are also in the right order.
for(int i = 0; i < machines.size() - 1; i++)
if (! machines.get(i).getEnd_Dt().before(machines.get(i + 1).getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
I am using “not before” to mean “on or after”. Or to put it another way, I am requiring each start date to come stricty before the next start date, and if it doesn’t, I throw the exception. Edit: I didn’t know how to get the end date from your object type, so please substitute the correct getter call where I wrote getEnd_Dt()
.
If you additionally need to check that each machine has start date and end date in the right order (using the enhanced for
loop):
for (Machine m : machines)
if (m.getEnd_Dt().before(m.getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
As an aside, Java naming conventions don’t use underscores in names (except in a CONSTANT_NAME
), so prefer getStrtDt
over getStrt_Dt
. Or even better, getStartDate
.
That said, Embid123 is correct, you should see if you can replace Date
with LocalDate
. The Date
class has design problems and is long outdated. And despite its name it doesn’t represent a date, but a point in time. LocalDate
is part of java.time, the modern Java date and time API, which is so much nicer to work with.
The other thing you need is to have your database query sort the entries by start date, then you know you get them in the right order.
What went wrong in your code?
First, your code is complicated on the border of the unreadable.
Next, when two entries i
and j
have start dates in the wrong order, that is, the j
date is earlier than the i
date, then machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
is negative and machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()
is positive. It’s really the same comparison, only reversed. So the product will be negative, your >= 0
condition will be false and you will not throw the exception.
Only if two entries have the exact same date (down to the millisecond), compareTo
returns 0, the product is 0, >= 0
will be true and your exception will be thrown.
Thank you. But, I need to validate both start date as well as end date should be less than the next object date.. Do I need to add multiple conditions?
– Syed
Nov 15 '18 at 12:27
Can you please modify the example if possible .. I'm not able to get it..
– Syed
Nov 15 '18 at 13:47
Thanks first of all.. But You are just checking the start date should be less than end date.. I requested you that the start date and end date of the first day should be less than start day and end day of the next object in the list. Hence both should be compared with the next level.
– Syed
Nov 16 '18 at 2:29
Just use the second loop too. When you have checked that the start date of the first date is not later than the end date, and the end date is before the next start date, and that start date is also before or on the corresponding end date, then if follows that both start and end date of the first thingie are before both start and end date of the second thingie. And so forth for the entire list.
– Ole V.V.
Nov 16 '18 at 7:53
add a comment |
tl;dr
Use the modern java.time.LocalDate
and org.threeten.extra.LocalDateRange
classes to simplify your business logic to basically one line asking if the prior item in the list is not before the current item.
if (
!
prior
.getDateRange()
.isBefore(
current.getDateRange()
)
) … handle rule violation …
See also the correct Answer by Ole V.V.
Avoid legacy date-time classes
Never use the badly-designed legacy classes. The java.util.Date
class, despite its name, represents a moment, a date with a time-of-day in UTC. The java.sql.Date
class pretends to represent a date-only but actually involves a time-of-day and offset as well.
java.time
The modern approach uses the java.time classes.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month
enum objects pre-defined, one for each month of the year. Tip: Use these Month
objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
You can directly parse strings in standard ISO 8601 format: YYYY-MM-DD
LocalDate ld = LocalDate.parse( "2018-01-23" ) ;
For parsing other formats, search Stack Overflow to learn about DateTimeFormatter
.
LocalDateRange
You seem to using a pair of dates, a start and stop date, in your Machine
class.
There is a class for that. Add the ThreeTen-Extra library to your project to access the LocalDateRange
class. This class has some very useful methods for comparing. Using this class greatly simplifies your code, and makes the intent of your business logic more obvious.
Store your stop/start dates as a LocalDateRange
object on your Machine
object.
private LocalDateRange dateRange;
Half-Open
Generally the best approach to tracking a span of time is the Half-Open approach. The beginning is inclusive while the ending is exclusive.
So a week is defined as starting on one day, such as Monday, and running up to, but not including, the same day of the following week, the next Monday for example. A year starts on January 1 of one year and runs up to, but does include, January 1 of the following year.
Using Half-Open approach would mean defining your example date like the following. Notice how changing the ending date to the year-long values in rows 1, 3, and 4 matches up with your own definition of the apparent month-long values of rows 2 & 5.
STRT_DT END_DT
---------- ----------
2014-01-01 2015-01-01
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2017-01-01
2017-01-01 2018-01-01
2018-01-01 2018-02-01
Example class: Machine
Here is some example code for your class Machine
.
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
public class Machine --------------------------
public String getName ( )
return this.name;
public LocalDateRange getDateRange ( )
return this.dateRange;
// -------
Let's try this class by writing a main
method.
public static void main ( String args )
List < Machine > machines =
List.of(
new Machine( "one" , LocalDate.parse( "2014-01-01" ) , LocalDate.parse( "2015-01-01" ) ) ,
new Machine( "two" , LocalDate.parse( "2013-01-01" ) , LocalDate.parse( "2013-02-01" ) ) , // Violates rule, where date-range should be *after* the prior one.
new Machine( "three" , LocalDate.parse( "2016-01-01" ) , LocalDate.parse( "2017-01-01" ) ) ,
new Machine( "four" , LocalDate.parse( "2017-01-01" ) , LocalDate.parse( "2018-01-01" ) ) ,
new Machine( "five" , LocalDate.parse( "2018-01-01" ) , LocalDate.parse( "2018-02-01" ) )
);
// Compare
for ( int i = 1 ; i < machines.size() ; i++ ) // Using annoying zero-based index counting.
Machine prior = machines.get( i - 1 );
Machine current = machines.get( i );
if ( ! prior.getDateRange().isBefore( current.getDateRange() ) )
System.out.println( "BAD: Machine at index " + ( i - 1 ) + " is not before Machine at index " + i + " ➙ " + prior.getDateRange().toString() + " versus " + current.getDateRange().toString() );
When run.
BAD: Machine at index 0 is not before Machine at index 1 ➙ 2014-01-01/2015-01-01 versus 2013-01-01/2013-02-01
JDBC 4.2
As of JDBC 4.2 and later, we can directly exchange java.time objects with the database.
LocalDate start = myResultSet.getObject( "start_date" , LocalDate.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
add a comment |
Are you using LocalDate? I think it is a good choice for comparing dates. It is since Java 8.
package sample;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class LocalDateTest
public static void main(String args)
//of(year, month, day)
LocalDate date1 = LocalDate.of(2018, 11, 11);
LocalDate date2 = LocalDate.of(2018, 11, 14);
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println(daysBetween);
LocalDate hasn't got any public constructor, you create an object via static factory method.
By the use of enum ChronoUnit, you get a long value representing days, weeks, or years from one date do second date. If you want to e.g. calculate weeks between, simply replace DAYS with WEEKS.
Now comparing dates is simple, if the value is negative, the first date exceeds the second one.
Documentation of LocalDate: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
I'm not using LocalDate..Its Java.util.Date and this comparision should happen between list of objects
– Syed
Nov 14 '18 at 10:38
This Answer does not address the Question. The Question asked about working a with a list of items, each having a pair of dates. The Question asked about comparing the pairs of dates, not elapsed days.
– Basil Bourque
Nov 14 '18 at 23:15
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%2f53297784%2fcomparing-date-with-next-object-date-in-arraylist-not-working-as-expected%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
You’re over-complicating it. It’s enough to check pairwise entries since if a < b are in the right order and b < c are in the right order, then you already know that a < c are also in the right order.
for(int i = 0; i < machines.size() - 1; i++)
if (! machines.get(i).getEnd_Dt().before(machines.get(i + 1).getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
I am using “not before” to mean “on or after”. Or to put it another way, I am requiring each start date to come stricty before the next start date, and if it doesn’t, I throw the exception. Edit: I didn’t know how to get the end date from your object type, so please substitute the correct getter call where I wrote getEnd_Dt()
.
If you additionally need to check that each machine has start date and end date in the right order (using the enhanced for
loop):
for (Machine m : machines)
if (m.getEnd_Dt().before(m.getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
As an aside, Java naming conventions don’t use underscores in names (except in a CONSTANT_NAME
), so prefer getStrtDt
over getStrt_Dt
. Or even better, getStartDate
.
That said, Embid123 is correct, you should see if you can replace Date
with LocalDate
. The Date
class has design problems and is long outdated. And despite its name it doesn’t represent a date, but a point in time. LocalDate
is part of java.time, the modern Java date and time API, which is so much nicer to work with.
The other thing you need is to have your database query sort the entries by start date, then you know you get them in the right order.
What went wrong in your code?
First, your code is complicated on the border of the unreadable.
Next, when two entries i
and j
have start dates in the wrong order, that is, the j
date is earlier than the i
date, then machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
is negative and machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()
is positive. It’s really the same comparison, only reversed. So the product will be negative, your >= 0
condition will be false and you will not throw the exception.
Only if two entries have the exact same date (down to the millisecond), compareTo
returns 0, the product is 0, >= 0
will be true and your exception will be thrown.
Thank you. But, I need to validate both start date as well as end date should be less than the next object date.. Do I need to add multiple conditions?
– Syed
Nov 15 '18 at 12:27
Can you please modify the example if possible .. I'm not able to get it..
– Syed
Nov 15 '18 at 13:47
Thanks first of all.. But You are just checking the start date should be less than end date.. I requested you that the start date and end date of the first day should be less than start day and end day of the next object in the list. Hence both should be compared with the next level.
– Syed
Nov 16 '18 at 2:29
Just use the second loop too. When you have checked that the start date of the first date is not later than the end date, and the end date is before the next start date, and that start date is also before or on the corresponding end date, then if follows that both start and end date of the first thingie are before both start and end date of the second thingie. And so forth for the entire list.
– Ole V.V.
Nov 16 '18 at 7:53
add a comment |
You’re over-complicating it. It’s enough to check pairwise entries since if a < b are in the right order and b < c are in the right order, then you already know that a < c are also in the right order.
for(int i = 0; i < machines.size() - 1; i++)
if (! machines.get(i).getEnd_Dt().before(machines.get(i + 1).getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
I am using “not before” to mean “on or after”. Or to put it another way, I am requiring each start date to come stricty before the next start date, and if it doesn’t, I throw the exception. Edit: I didn’t know how to get the end date from your object type, so please substitute the correct getter call where I wrote getEnd_Dt()
.
If you additionally need to check that each machine has start date and end date in the right order (using the enhanced for
loop):
for (Machine m : machines)
if (m.getEnd_Dt().before(m.getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
As an aside, Java naming conventions don’t use underscores in names (except in a CONSTANT_NAME
), so prefer getStrtDt
over getStrt_Dt
. Or even better, getStartDate
.
That said, Embid123 is correct, you should see if you can replace Date
with LocalDate
. The Date
class has design problems and is long outdated. And despite its name it doesn’t represent a date, but a point in time. LocalDate
is part of java.time, the modern Java date and time API, which is so much nicer to work with.
The other thing you need is to have your database query sort the entries by start date, then you know you get them in the right order.
What went wrong in your code?
First, your code is complicated on the border of the unreadable.
Next, when two entries i
and j
have start dates in the wrong order, that is, the j
date is earlier than the i
date, then machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
is negative and machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()
is positive. It’s really the same comparison, only reversed. So the product will be negative, your >= 0
condition will be false and you will not throw the exception.
Only if two entries have the exact same date (down to the millisecond), compareTo
returns 0, the product is 0, >= 0
will be true and your exception will be thrown.
Thank you. But, I need to validate both start date as well as end date should be less than the next object date.. Do I need to add multiple conditions?
– Syed
Nov 15 '18 at 12:27
Can you please modify the example if possible .. I'm not able to get it..
– Syed
Nov 15 '18 at 13:47
Thanks first of all.. But You are just checking the start date should be less than end date.. I requested you that the start date and end date of the first day should be less than start day and end day of the next object in the list. Hence both should be compared with the next level.
– Syed
Nov 16 '18 at 2:29
Just use the second loop too. When you have checked that the start date of the first date is not later than the end date, and the end date is before the next start date, and that start date is also before or on the corresponding end date, then if follows that both start and end date of the first thingie are before both start and end date of the second thingie. And so forth for the entire list.
– Ole V.V.
Nov 16 '18 at 7:53
add a comment |
You’re over-complicating it. It’s enough to check pairwise entries since if a < b are in the right order and b < c are in the right order, then you already know that a < c are also in the right order.
for(int i = 0; i < machines.size() - 1; i++)
if (! machines.get(i).getEnd_Dt().before(machines.get(i + 1).getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
I am using “not before” to mean “on or after”. Or to put it another way, I am requiring each start date to come stricty before the next start date, and if it doesn’t, I throw the exception. Edit: I didn’t know how to get the end date from your object type, so please substitute the correct getter call where I wrote getEnd_Dt()
.
If you additionally need to check that each machine has start date and end date in the right order (using the enhanced for
loop):
for (Machine m : machines)
if (m.getEnd_Dt().before(m.getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
As an aside, Java naming conventions don’t use underscores in names (except in a CONSTANT_NAME
), so prefer getStrtDt
over getStrt_Dt
. Or even better, getStartDate
.
That said, Embid123 is correct, you should see if you can replace Date
with LocalDate
. The Date
class has design problems and is long outdated. And despite its name it doesn’t represent a date, but a point in time. LocalDate
is part of java.time, the modern Java date and time API, which is so much nicer to work with.
The other thing you need is to have your database query sort the entries by start date, then you know you get them in the right order.
What went wrong in your code?
First, your code is complicated on the border of the unreadable.
Next, when two entries i
and j
have start dates in the wrong order, that is, the j
date is earlier than the i
date, then machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
is negative and machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()
is positive. It’s really the same comparison, only reversed. So the product will be negative, your >= 0
condition will be false and you will not throw the exception.
Only if two entries have the exact same date (down to the millisecond), compareTo
returns 0, the product is 0, >= 0
will be true and your exception will be thrown.
You’re over-complicating it. It’s enough to check pairwise entries since if a < b are in the right order and b < c are in the right order, then you already know that a < c are also in the right order.
for(int i = 0; i < machines.size() - 1; i++)
if (! machines.get(i).getEnd_Dt().before(machines.get(i + 1).getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
I am using “not before” to mean “on or after”. Or to put it another way, I am requiring each start date to come stricty before the next start date, and if it doesn’t, I throw the exception. Edit: I didn’t know how to get the end date from your object type, so please substitute the correct getter call where I wrote getEnd_Dt()
.
If you additionally need to check that each machine has start date and end date in the right order (using the enhanced for
loop):
for (Machine m : machines)
if (m.getEnd_Dt().before(m.getStrt_Dt()))
throw new IllegalStateException("Dates are not in chronological order");
As an aside, Java naming conventions don’t use underscores in names (except in a CONSTANT_NAME
), so prefer getStrtDt
over getStrt_Dt
. Or even better, getStartDate
.
That said, Embid123 is correct, you should see if you can replace Date
with LocalDate
. The Date
class has design problems and is long outdated. And despite its name it doesn’t represent a date, but a point in time. LocalDate
is part of java.time, the modern Java date and time API, which is so much nicer to work with.
The other thing you need is to have your database query sort the entries by start date, then you know you get them in the right order.
What went wrong in your code?
First, your code is complicated on the border of the unreadable.
Next, when two entries i
and j
have start dates in the wrong order, that is, the j
date is earlier than the i
date, then machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
is negative and machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()
is positive. It’s really the same comparison, only reversed. So the product will be negative, your >= 0
condition will be false and you will not throw the exception.
Only if two entries have the exact same date (down to the millisecond), compareTo
returns 0, the product is 0, >= 0
will be true and your exception will be thrown.
edited Nov 15 '18 at 19:42
answered Nov 14 '18 at 11:45
Ole V.V.Ole V.V.
28.8k63352
28.8k63352
Thank you. But, I need to validate both start date as well as end date should be less than the next object date.. Do I need to add multiple conditions?
– Syed
Nov 15 '18 at 12:27
Can you please modify the example if possible .. I'm not able to get it..
– Syed
Nov 15 '18 at 13:47
Thanks first of all.. But You are just checking the start date should be less than end date.. I requested you that the start date and end date of the first day should be less than start day and end day of the next object in the list. Hence both should be compared with the next level.
– Syed
Nov 16 '18 at 2:29
Just use the second loop too. When you have checked that the start date of the first date is not later than the end date, and the end date is before the next start date, and that start date is also before or on the corresponding end date, then if follows that both start and end date of the first thingie are before both start and end date of the second thingie. And so forth for the entire list.
– Ole V.V.
Nov 16 '18 at 7:53
add a comment |
Thank you. But, I need to validate both start date as well as end date should be less than the next object date.. Do I need to add multiple conditions?
– Syed
Nov 15 '18 at 12:27
Can you please modify the example if possible .. I'm not able to get it..
– Syed
Nov 15 '18 at 13:47
Thanks first of all.. But You are just checking the start date should be less than end date.. I requested you that the start date and end date of the first day should be less than start day and end day of the next object in the list. Hence both should be compared with the next level.
– Syed
Nov 16 '18 at 2:29
Just use the second loop too. When you have checked that the start date of the first date is not later than the end date, and the end date is before the next start date, and that start date is also before or on the corresponding end date, then if follows that both start and end date of the first thingie are before both start and end date of the second thingie. And so forth for the entire list.
– Ole V.V.
Nov 16 '18 at 7:53
Thank you. But, I need to validate both start date as well as end date should be less than the next object date.. Do I need to add multiple conditions?
– Syed
Nov 15 '18 at 12:27
Thank you. But, I need to validate both start date as well as end date should be less than the next object date.. Do I need to add multiple conditions?
– Syed
Nov 15 '18 at 12:27
Can you please modify the example if possible .. I'm not able to get it..
– Syed
Nov 15 '18 at 13:47
Can you please modify the example if possible .. I'm not able to get it..
– Syed
Nov 15 '18 at 13:47
Thanks first of all.. But You are just checking the start date should be less than end date.. I requested you that the start date and end date of the first day should be less than start day and end day of the next object in the list. Hence both should be compared with the next level.
– Syed
Nov 16 '18 at 2:29
Thanks first of all.. But You are just checking the start date should be less than end date.. I requested you that the start date and end date of the first day should be less than start day and end day of the next object in the list. Hence both should be compared with the next level.
– Syed
Nov 16 '18 at 2:29
Just use the second loop too. When you have checked that the start date of the first date is not later than the end date, and the end date is before the next start date, and that start date is also before or on the corresponding end date, then if follows that both start and end date of the first thingie are before both start and end date of the second thingie. And so forth for the entire list.
– Ole V.V.
Nov 16 '18 at 7:53
Just use the second loop too. When you have checked that the start date of the first date is not later than the end date, and the end date is before the next start date, and that start date is also before or on the corresponding end date, then if follows that both start and end date of the first thingie are before both start and end date of the second thingie. And so forth for the entire list.
– Ole V.V.
Nov 16 '18 at 7:53
add a comment |
tl;dr
Use the modern java.time.LocalDate
and org.threeten.extra.LocalDateRange
classes to simplify your business logic to basically one line asking if the prior item in the list is not before the current item.
if (
!
prior
.getDateRange()
.isBefore(
current.getDateRange()
)
) … handle rule violation …
See also the correct Answer by Ole V.V.
Avoid legacy date-time classes
Never use the badly-designed legacy classes. The java.util.Date
class, despite its name, represents a moment, a date with a time-of-day in UTC. The java.sql.Date
class pretends to represent a date-only but actually involves a time-of-day and offset as well.
java.time
The modern approach uses the java.time classes.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month
enum objects pre-defined, one for each month of the year. Tip: Use these Month
objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
You can directly parse strings in standard ISO 8601 format: YYYY-MM-DD
LocalDate ld = LocalDate.parse( "2018-01-23" ) ;
For parsing other formats, search Stack Overflow to learn about DateTimeFormatter
.
LocalDateRange
You seem to using a pair of dates, a start and stop date, in your Machine
class.
There is a class for that. Add the ThreeTen-Extra library to your project to access the LocalDateRange
class. This class has some very useful methods for comparing. Using this class greatly simplifies your code, and makes the intent of your business logic more obvious.
Store your stop/start dates as a LocalDateRange
object on your Machine
object.
private LocalDateRange dateRange;
Half-Open
Generally the best approach to tracking a span of time is the Half-Open approach. The beginning is inclusive while the ending is exclusive.
So a week is defined as starting on one day, such as Monday, and running up to, but not including, the same day of the following week, the next Monday for example. A year starts on January 1 of one year and runs up to, but does include, January 1 of the following year.
Using Half-Open approach would mean defining your example date like the following. Notice how changing the ending date to the year-long values in rows 1, 3, and 4 matches up with your own definition of the apparent month-long values of rows 2 & 5.
STRT_DT END_DT
---------- ----------
2014-01-01 2015-01-01
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2017-01-01
2017-01-01 2018-01-01
2018-01-01 2018-02-01
Example class: Machine
Here is some example code for your class Machine
.
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
public class Machine --------------------------
public String getName ( )
return this.name;
public LocalDateRange getDateRange ( )
return this.dateRange;
// -------
Let's try this class by writing a main
method.
public static void main ( String args )
List < Machine > machines =
List.of(
new Machine( "one" , LocalDate.parse( "2014-01-01" ) , LocalDate.parse( "2015-01-01" ) ) ,
new Machine( "two" , LocalDate.parse( "2013-01-01" ) , LocalDate.parse( "2013-02-01" ) ) , // Violates rule, where date-range should be *after* the prior one.
new Machine( "three" , LocalDate.parse( "2016-01-01" ) , LocalDate.parse( "2017-01-01" ) ) ,
new Machine( "four" , LocalDate.parse( "2017-01-01" ) , LocalDate.parse( "2018-01-01" ) ) ,
new Machine( "five" , LocalDate.parse( "2018-01-01" ) , LocalDate.parse( "2018-02-01" ) )
);
// Compare
for ( int i = 1 ; i < machines.size() ; i++ ) // Using annoying zero-based index counting.
Machine prior = machines.get( i - 1 );
Machine current = machines.get( i );
if ( ! prior.getDateRange().isBefore( current.getDateRange() ) )
System.out.println( "BAD: Machine at index " + ( i - 1 ) + " is not before Machine at index " + i + " ➙ " + prior.getDateRange().toString() + " versus " + current.getDateRange().toString() );
When run.
BAD: Machine at index 0 is not before Machine at index 1 ➙ 2014-01-01/2015-01-01 versus 2013-01-01/2013-02-01
JDBC 4.2
As of JDBC 4.2 and later, we can directly exchange java.time objects with the database.
LocalDate start = myResultSet.getObject( "start_date" , LocalDate.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
add a comment |
tl;dr
Use the modern java.time.LocalDate
and org.threeten.extra.LocalDateRange
classes to simplify your business logic to basically one line asking if the prior item in the list is not before the current item.
if (
!
prior
.getDateRange()
.isBefore(
current.getDateRange()
)
) … handle rule violation …
See also the correct Answer by Ole V.V.
Avoid legacy date-time classes
Never use the badly-designed legacy classes. The java.util.Date
class, despite its name, represents a moment, a date with a time-of-day in UTC. The java.sql.Date
class pretends to represent a date-only but actually involves a time-of-day and offset as well.
java.time
The modern approach uses the java.time classes.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month
enum objects pre-defined, one for each month of the year. Tip: Use these Month
objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
You can directly parse strings in standard ISO 8601 format: YYYY-MM-DD
LocalDate ld = LocalDate.parse( "2018-01-23" ) ;
For parsing other formats, search Stack Overflow to learn about DateTimeFormatter
.
LocalDateRange
You seem to using a pair of dates, a start and stop date, in your Machine
class.
There is a class for that. Add the ThreeTen-Extra library to your project to access the LocalDateRange
class. This class has some very useful methods for comparing. Using this class greatly simplifies your code, and makes the intent of your business logic more obvious.
Store your stop/start dates as a LocalDateRange
object on your Machine
object.
private LocalDateRange dateRange;
Half-Open
Generally the best approach to tracking a span of time is the Half-Open approach. The beginning is inclusive while the ending is exclusive.
So a week is defined as starting on one day, such as Monday, and running up to, but not including, the same day of the following week, the next Monday for example. A year starts on January 1 of one year and runs up to, but does include, January 1 of the following year.
Using Half-Open approach would mean defining your example date like the following. Notice how changing the ending date to the year-long values in rows 1, 3, and 4 matches up with your own definition of the apparent month-long values of rows 2 & 5.
STRT_DT END_DT
---------- ----------
2014-01-01 2015-01-01
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2017-01-01
2017-01-01 2018-01-01
2018-01-01 2018-02-01
Example class: Machine
Here is some example code for your class Machine
.
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
public class Machine --------------------------
public String getName ( )
return this.name;
public LocalDateRange getDateRange ( )
return this.dateRange;
// -------
Let's try this class by writing a main
method.
public static void main ( String args )
List < Machine > machines =
List.of(
new Machine( "one" , LocalDate.parse( "2014-01-01" ) , LocalDate.parse( "2015-01-01" ) ) ,
new Machine( "two" , LocalDate.parse( "2013-01-01" ) , LocalDate.parse( "2013-02-01" ) ) , // Violates rule, where date-range should be *after* the prior one.
new Machine( "three" , LocalDate.parse( "2016-01-01" ) , LocalDate.parse( "2017-01-01" ) ) ,
new Machine( "four" , LocalDate.parse( "2017-01-01" ) , LocalDate.parse( "2018-01-01" ) ) ,
new Machine( "five" , LocalDate.parse( "2018-01-01" ) , LocalDate.parse( "2018-02-01" ) )
);
// Compare
for ( int i = 1 ; i < machines.size() ; i++ ) // Using annoying zero-based index counting.
Machine prior = machines.get( i - 1 );
Machine current = machines.get( i );
if ( ! prior.getDateRange().isBefore( current.getDateRange() ) )
System.out.println( "BAD: Machine at index " + ( i - 1 ) + " is not before Machine at index " + i + " ➙ " + prior.getDateRange().toString() + " versus " + current.getDateRange().toString() );
When run.
BAD: Machine at index 0 is not before Machine at index 1 ➙ 2014-01-01/2015-01-01 versus 2013-01-01/2013-02-01
JDBC 4.2
As of JDBC 4.2 and later, we can directly exchange java.time objects with the database.
LocalDate start = myResultSet.getObject( "start_date" , LocalDate.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
add a comment |
tl;dr
Use the modern java.time.LocalDate
and org.threeten.extra.LocalDateRange
classes to simplify your business logic to basically one line asking if the prior item in the list is not before the current item.
if (
!
prior
.getDateRange()
.isBefore(
current.getDateRange()
)
) … handle rule violation …
See also the correct Answer by Ole V.V.
Avoid legacy date-time classes
Never use the badly-designed legacy classes. The java.util.Date
class, despite its name, represents a moment, a date with a time-of-day in UTC. The java.sql.Date
class pretends to represent a date-only but actually involves a time-of-day and offset as well.
java.time
The modern approach uses the java.time classes.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month
enum objects pre-defined, one for each month of the year. Tip: Use these Month
objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
You can directly parse strings in standard ISO 8601 format: YYYY-MM-DD
LocalDate ld = LocalDate.parse( "2018-01-23" ) ;
For parsing other formats, search Stack Overflow to learn about DateTimeFormatter
.
LocalDateRange
You seem to using a pair of dates, a start and stop date, in your Machine
class.
There is a class for that. Add the ThreeTen-Extra library to your project to access the LocalDateRange
class. This class has some very useful methods for comparing. Using this class greatly simplifies your code, and makes the intent of your business logic more obvious.
Store your stop/start dates as a LocalDateRange
object on your Machine
object.
private LocalDateRange dateRange;
Half-Open
Generally the best approach to tracking a span of time is the Half-Open approach. The beginning is inclusive while the ending is exclusive.
So a week is defined as starting on one day, such as Monday, and running up to, but not including, the same day of the following week, the next Monday for example. A year starts on January 1 of one year and runs up to, but does include, January 1 of the following year.
Using Half-Open approach would mean defining your example date like the following. Notice how changing the ending date to the year-long values in rows 1, 3, and 4 matches up with your own definition of the apparent month-long values of rows 2 & 5.
STRT_DT END_DT
---------- ----------
2014-01-01 2015-01-01
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2017-01-01
2017-01-01 2018-01-01
2018-01-01 2018-02-01
Example class: Machine
Here is some example code for your class Machine
.
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
public class Machine --------------------------
public String getName ( )
return this.name;
public LocalDateRange getDateRange ( )
return this.dateRange;
// -------
Let's try this class by writing a main
method.
public static void main ( String args )
List < Machine > machines =
List.of(
new Machine( "one" , LocalDate.parse( "2014-01-01" ) , LocalDate.parse( "2015-01-01" ) ) ,
new Machine( "two" , LocalDate.parse( "2013-01-01" ) , LocalDate.parse( "2013-02-01" ) ) , // Violates rule, where date-range should be *after* the prior one.
new Machine( "three" , LocalDate.parse( "2016-01-01" ) , LocalDate.parse( "2017-01-01" ) ) ,
new Machine( "four" , LocalDate.parse( "2017-01-01" ) , LocalDate.parse( "2018-01-01" ) ) ,
new Machine( "five" , LocalDate.parse( "2018-01-01" ) , LocalDate.parse( "2018-02-01" ) )
);
// Compare
for ( int i = 1 ; i < machines.size() ; i++ ) // Using annoying zero-based index counting.
Machine prior = machines.get( i - 1 );
Machine current = machines.get( i );
if ( ! prior.getDateRange().isBefore( current.getDateRange() ) )
System.out.println( "BAD: Machine at index " + ( i - 1 ) + " is not before Machine at index " + i + " ➙ " + prior.getDateRange().toString() + " versus " + current.getDateRange().toString() );
When run.
BAD: Machine at index 0 is not before Machine at index 1 ➙ 2014-01-01/2015-01-01 versus 2013-01-01/2013-02-01
JDBC 4.2
As of JDBC 4.2 and later, we can directly exchange java.time objects with the database.
LocalDate start = myResultSet.getObject( "start_date" , LocalDate.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
tl;dr
Use the modern java.time.LocalDate
and org.threeten.extra.LocalDateRange
classes to simplify your business logic to basically one line asking if the prior item in the list is not before the current item.
if (
!
prior
.getDateRange()
.isBefore(
current.getDateRange()
)
) … handle rule violation …
See also the correct Answer by Ole V.V.
Avoid legacy date-time classes
Never use the badly-designed legacy classes. The java.util.Date
class, despite its name, represents a moment, a date with a time-of-day in UTC. The java.sql.Date
class pretends to represent a date-only but actually involves a time-of-day and offset as well.
java.time
The modern approach uses the java.time classes.
LocalDate
The LocalDate
class represents a date-only value without time-of-day and without time zone or offset-from-UTC.
You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month
enum objects pre-defined, one for each month of the year. Tip: Use these Month
objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
You can directly parse strings in standard ISO 8601 format: YYYY-MM-DD
LocalDate ld = LocalDate.parse( "2018-01-23" ) ;
For parsing other formats, search Stack Overflow to learn about DateTimeFormatter
.
LocalDateRange
You seem to using a pair of dates, a start and stop date, in your Machine
class.
There is a class for that. Add the ThreeTen-Extra library to your project to access the LocalDateRange
class. This class has some very useful methods for comparing. Using this class greatly simplifies your code, and makes the intent of your business logic more obvious.
Store your stop/start dates as a LocalDateRange
object on your Machine
object.
private LocalDateRange dateRange;
Half-Open
Generally the best approach to tracking a span of time is the Half-Open approach. The beginning is inclusive while the ending is exclusive.
So a week is defined as starting on one day, such as Monday, and running up to, but not including, the same day of the following week, the next Monday for example. A year starts on January 1 of one year and runs up to, but does include, January 1 of the following year.
Using Half-Open approach would mean defining your example date like the following. Notice how changing the ending date to the year-long values in rows 1, 3, and 4 matches up with your own definition of the apparent month-long values of rows 2 & 5.
STRT_DT END_DT
---------- ----------
2014-01-01 2015-01-01
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2017-01-01
2017-01-01 2018-01-01
2018-01-01 2018-02-01
Example class: Machine
Here is some example code for your class Machine
.
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
public class Machine --------------------------
public String getName ( )
return this.name;
public LocalDateRange getDateRange ( )
return this.dateRange;
// -------
Let's try this class by writing a main
method.
public static void main ( String args )
List < Machine > machines =
List.of(
new Machine( "one" , LocalDate.parse( "2014-01-01" ) , LocalDate.parse( "2015-01-01" ) ) ,
new Machine( "two" , LocalDate.parse( "2013-01-01" ) , LocalDate.parse( "2013-02-01" ) ) , // Violates rule, where date-range should be *after* the prior one.
new Machine( "three" , LocalDate.parse( "2016-01-01" ) , LocalDate.parse( "2017-01-01" ) ) ,
new Machine( "four" , LocalDate.parse( "2017-01-01" ) , LocalDate.parse( "2018-01-01" ) ) ,
new Machine( "five" , LocalDate.parse( "2018-01-01" ) , LocalDate.parse( "2018-02-01" ) )
);
// Compare
for ( int i = 1 ; i < machines.size() ; i++ ) // Using annoying zero-based index counting.
Machine prior = machines.get( i - 1 );
Machine current = machines.get( i );
if ( ! prior.getDateRange().isBefore( current.getDateRange() ) )
System.out.println( "BAD: Machine at index " + ( i - 1 ) + " is not before Machine at index " + i + " ➙ " + prior.getDateRange().toString() + " versus " + current.getDateRange().toString() );
When run.
BAD: Machine at index 0 is not before Machine at index 1 ➙ 2014-01-01/2015-01-01 versus 2013-01-01/2013-02-01
JDBC 4.2
As of JDBC 4.2 and later, we can directly exchange java.time objects with the database.
LocalDate start = myResultSet.getObject( "start_date" , LocalDate.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.- Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
edited Nov 15 '18 at 20:52
answered Nov 14 '18 at 23:10
Basil BourqueBasil Bourque
111k27378542
111k27378542
add a comment |
add a comment |
Are you using LocalDate? I think it is a good choice for comparing dates. It is since Java 8.
package sample;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class LocalDateTest
public static void main(String args)
//of(year, month, day)
LocalDate date1 = LocalDate.of(2018, 11, 11);
LocalDate date2 = LocalDate.of(2018, 11, 14);
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println(daysBetween);
LocalDate hasn't got any public constructor, you create an object via static factory method.
By the use of enum ChronoUnit, you get a long value representing days, weeks, or years from one date do second date. If you want to e.g. calculate weeks between, simply replace DAYS with WEEKS.
Now comparing dates is simple, if the value is negative, the first date exceeds the second one.
Documentation of LocalDate: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
I'm not using LocalDate..Its Java.util.Date and this comparision should happen between list of objects
– Syed
Nov 14 '18 at 10:38
This Answer does not address the Question. The Question asked about working a with a list of items, each having a pair of dates. The Question asked about comparing the pairs of dates, not elapsed days.
– Basil Bourque
Nov 14 '18 at 23:15
add a comment |
Are you using LocalDate? I think it is a good choice for comparing dates. It is since Java 8.
package sample;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class LocalDateTest
public static void main(String args)
//of(year, month, day)
LocalDate date1 = LocalDate.of(2018, 11, 11);
LocalDate date2 = LocalDate.of(2018, 11, 14);
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println(daysBetween);
LocalDate hasn't got any public constructor, you create an object via static factory method.
By the use of enum ChronoUnit, you get a long value representing days, weeks, or years from one date do second date. If you want to e.g. calculate weeks between, simply replace DAYS with WEEKS.
Now comparing dates is simple, if the value is negative, the first date exceeds the second one.
Documentation of LocalDate: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
I'm not using LocalDate..Its Java.util.Date and this comparision should happen between list of objects
– Syed
Nov 14 '18 at 10:38
This Answer does not address the Question. The Question asked about working a with a list of items, each having a pair of dates. The Question asked about comparing the pairs of dates, not elapsed days.
– Basil Bourque
Nov 14 '18 at 23:15
add a comment |
Are you using LocalDate? I think it is a good choice for comparing dates. It is since Java 8.
package sample;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class LocalDateTest
public static void main(String args)
//of(year, month, day)
LocalDate date1 = LocalDate.of(2018, 11, 11);
LocalDate date2 = LocalDate.of(2018, 11, 14);
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println(daysBetween);
LocalDate hasn't got any public constructor, you create an object via static factory method.
By the use of enum ChronoUnit, you get a long value representing days, weeks, or years from one date do second date. If you want to e.g. calculate weeks between, simply replace DAYS with WEEKS.
Now comparing dates is simple, if the value is negative, the first date exceeds the second one.
Documentation of LocalDate: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
Are you using LocalDate? I think it is a good choice for comparing dates. It is since Java 8.
package sample;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class LocalDateTest
public static void main(String args)
//of(year, month, day)
LocalDate date1 = LocalDate.of(2018, 11, 11);
LocalDate date2 = LocalDate.of(2018, 11, 14);
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println(daysBetween);
LocalDate hasn't got any public constructor, you create an object via static factory method.
By the use of enum ChronoUnit, you get a long value representing days, weeks, or years from one date do second date. If you want to e.g. calculate weeks between, simply replace DAYS with WEEKS.
Now comparing dates is simple, if the value is negative, the first date exceeds the second one.
Documentation of LocalDate: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
answered Nov 14 '18 at 10:34
Embid123Embid123
25410
25410
I'm not using LocalDate..Its Java.util.Date and this comparision should happen between list of objects
– Syed
Nov 14 '18 at 10:38
This Answer does not address the Question. The Question asked about working a with a list of items, each having a pair of dates. The Question asked about comparing the pairs of dates, not elapsed days.
– Basil Bourque
Nov 14 '18 at 23:15
add a comment |
I'm not using LocalDate..Its Java.util.Date and this comparision should happen between list of objects
– Syed
Nov 14 '18 at 10:38
This Answer does not address the Question. The Question asked about working a with a list of items, each having a pair of dates. The Question asked about comparing the pairs of dates, not elapsed days.
– Basil Bourque
Nov 14 '18 at 23:15
I'm not using LocalDate..Its Java.util.Date and this comparision should happen between list of objects
– Syed
Nov 14 '18 at 10:38
I'm not using LocalDate..Its Java.util.Date and this comparision should happen between list of objects
– Syed
Nov 14 '18 at 10:38
This Answer does not address the Question. The Question asked about working a with a list of items, each having a pair of dates. The Question asked about comparing the pairs of dates, not elapsed days.
– Basil Bourque
Nov 14 '18 at 23:15
This Answer does not address the Question. The Question asked about working a with a list of items, each having a pair of dates. The Question asked about comparing the pairs of dates, not elapsed days.
– Basil Bourque
Nov 14 '18 at 23:15
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%2f53297784%2fcomparing-date-with-next-object-date-in-arraylist-not-working-as-expected%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
1
Cannot understand why your if statement has the same condition ORed twice?
– robot_alien
Nov 14 '18 at 10:25
i * i > 0
, even ifi = -1
.– 孙兴斌
Nov 14 '18 at 10:26
Because my first record i would be checking with second record j
– Syed
Nov 14 '18 at 10:27
Is it enough that start dates come in the right order? Or do you need to check for overlaps in time too? I mean where one end date would come after the following start date.
– Ole V.V.
Nov 14 '18 at 11:39
Since you have an
ArrayList
you could also use alistIterator()
to get compare thenext()
and theprevious()
date-pairs.– LuCio
Nov 14 '18 at 11:47