Reputation: 942
I am trying filters with Java, I can't use "Select ..." for find results.
The problem is that my object always join in my array.
My datas are ->
Registro 1-> Fecha Inicio "2018-09-01" , Fecha Fin -> "2018-09-30"
Registro 2-> Fecha inicio "2018-10-01" , Fecha Fin -> "2018-10-05"
Registro 3-> Fecha inicio "2017-12-31" , Fecha Fin -> "2018-11-30"
Registro 4-> Fecha inicio "2018-12-01" , Fecha Fin -> "2019-10-01"
Registro 5-> Fecha inicio "2018-12-30" , Fecha Fin -> "2018-12-31"
Registro 6-> Fecha inicio "2018-11-30" , Fecha Fin -> "2018-12-01"
The user insert -> "2018-12-01" hasta el "9999-31-12"
for filter.
Register 4 should be insert to array because my user insert "2018-12-01" and my register have the same Date Start.
Register 5º should be insert to array because my user insert "2018-12-01" and finish year->9999
THEN how my register is between, It should insert to array.
Register 6º -> shold be insert to array because the date End because its end date corresponds to the period of time between the start date and the end date of the user, that is, the user wants between "2018-12-01" until "9999-31-12" and the date End of registration is "2018-12-01"
public List<Article> filterResult(String paramSelect, String dateStart, String dateEnd) {
List<Article> list = Collections.emptyList();
try {
// Sino me ponen fecha de fin, la establezco al máximo.
if(dateStart != null && dateEnd == null) {
dateEnd ="9999-31-12";
list = (List<Article>) this.pgRepository.findAll();
list = this.getStart(list, dateStart, dateEnd);
}
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
return list;
}
private List<Article> getStart(List<Article> list, String dateStart, String dateEnd) throws ParseException {
DateFomrat df = new SimpleDateFormat("yyyy-MM-dd");
Date userDate = df.parse(dateStart);
Date userEnd = df.parse(dateEnd);
List<Article> filter = new ArrayList<Article>();
for(Article param : list) {
Date paramStart = df.parse(param.getStartdatevalidity());
Date paramEnd = df.parse(param.getEnddatevalidity());
if(paramStart.after(userDate) || paramEnd.before(userDate) && paramStart.after(userEnd) || paramEnd.before(userEnd)) {
filter.add(param);
}
}
return filter;
}
I have two problems -> 1º My object always is guarded in my array. 2º I don't know if my logic is correct...
Thanks and sorry for my English.
Upvotes: 1
Views: 5447
Reputation: 86280
I think that you want this:
if (! (paramEnd.before(userDate) || paramStart.after(userEnd))) {
filter.add(param);
}
Yes, this simple. You may say that I have reversed the condition. You don’t want the articles whose validity end before userDate
, and you also don’t want those whose validity begin after userEnd
. All other articles have an overlap with the user interval, so are included.
That said, the Date
class that you are using is long outdated and has a number of design problems. And SimpleDateFormat
is renowned for trouble. Furthermore a Date
despite its name does not represent a date, but a point in time. I recommend you use LocalDate
from java.time, the modern Java date and time API, for representing a date, both inside your Article
class and in your search and filter code. As an added bonus LocalDate
parses your date format of yyyy-MM-dd
without any explicit formatter since this format is standard (it’s also known as ISO 8601). For example:
public class Article {
LocalDate startDateValidity;
LocalDate endDateValidity;
// Note that this constructor accepts string arguments for convenience
public Article(String startValidity, String endValidity) {
this.startDateValidity = LocalDate.parse(startValidity);
this.endDateValidity = LocalDate.parse(endValidity);
}
// getters etc.
}
In filterResult
parse dateStart
and dateEnd
into LocalDate
in the same say as in the constructor above. If dateEnd
is missing, set userEnd
tp LocalDate.MAX
. Your if
condition isn’t changed much when all the dates are LocalDate
; there’s an is
in front of the method names:
if (! (paramEnd.isBefore(userDate) || paramStart.isAfter(userEnd))) {
filter.add(param);
}
EDIT: let’s test it.
Using the dates of the 6 registrations from your question:
List<Article> list = Arrays.asList(
new Article("2018-09-01", "2018-09-30"),
new Article("2018-10-01", "2018-10-05"),
new Article("2017-12-31", "2018-11-30"),
new Article("2018-12-01", "2019-10-01"),
new Article("2018-12-30", "2018-12-31"),
new Article("2018-11-30", "2018-12-01"));
LocalDate userDate = LocalDate.parse("2018-12-01");
LocalDate userEnd = LocalDate.MAX;
for(Article param : list) {
LocalDate paramStart = param.getStartDateValidity();
LocalDate paramEnd = param.getEndDateValidity();
if (! (paramEnd.isBefore(userDate) || paramStart.isAfter(userEnd))) {
System.out.println("Included " + param);
}
}
This snippet printed the following output:
Included Article [startDateValidity=2018-12-01, endDateValidity=2019-10-01]
Included Article [startDateValidity=2018-12-30, endDateValidity=2018-12-31]
Included Article [startDateValidity=2018-11-30, endDateValidity=2018-12-01]
You will recognize the dates of registrations number 4, 5 and 6, which were the ones that you said you wanted to be inserted into your filter array.
I have two problems -> 1º My object always is guarded in my array. 2º I don't know if my logic is correct...
You are correct that your logic is incorrect. Let’s look at your if
condition:
if(paramStart.after(userDate)
|| paramEnd.before(userDate) && paramStart.after(userEnd)
|| paramEnd.before(userEnd)) …
&&
has higher precedence than ||
, so it is interpreted as though there were brackets around paramEnd.before(userDate) && paramStart.after(userEnd)
. This middle part of the condition will realistically never be true, though, but an article will be included if either the first or the last part is. Only registrations number 5 fulfils the first part of the condition because after
means “strictly after”. However all 6 registrations fulfil the last part, paramEnd.before(userDate) && paramStart.after(userEnd)
. With ||
between the parts this is enough that all 6 articles are included in the filter result.
java.time
.Upvotes: 3
Reputation: 1000
Edit 2 - removed questions asked here for more clarification as got the concept by Ole V.V's answer and I have upvoted it being clear helpful answer.
My suggestion based on provided details -
Using boolean java.util.Date.after(Date when)
//Change suggestion in original code
if(paramStart.after(userDate) || paramEnd.before(userDate) paramEnd.before(userEnd)) {
filter.add(param);
}
Using int java.util.Date.compareTo(java.util.Date anotherDate)
Upvotes: 0
Reputation: 18245
I offer not to use date parsing from String
to Date
at all. In case data is stored and entered by the user in the same format yyyy-mm-dd
, then to compare two dates it is enough just compare two strings.
P.S. Actually, to compare huge list of dates in same format, we use RadixSort for string.
In this case, your getStart()
method becomes very simple:
public static List<Article> getStart(List<Article> list, String dateStart, String dateEnd) {
final Predicate<String> isInRange = date -> date.compareTo(dateStart) >= 0 && date.compareTo(dateEnd) <= 0;
final Predicate<Article> isIntersect = article -> isInRange.test(article.getStartdatevalidity()) || isInRange.test(article.getEnddatevalidity());
return list.stream().filter(isIntersect).collect(Collectors.toList());
}
Upvotes: 0