Hot questions for Using Joda-Time in arraylist

Question:

Hello I am looking for a better way to determine existence of a date in a list of dates in Java using JodaTime. Currently this is what I am using:

private static void dateSearch() {
    ArrayList<Date> dates = new ArrayList<>(); 
    dates.add(formatDate("2016-08-18T05:18:24"));
    dates.add(formatDate("2016-08-17T05:18:24"));
    dates.add(formatDate("2016-08-19T17:00:24"));
    Collections.sort(dates);
    Date today=new Date();
    int index=Collections.binarySearch(dates,today,new DateComparator());
    if(index>=0){
        System.out.println("Todays date was found " + index);
    }
}

//Here is the formatDate Function that produces date objects from strings
private static Date formatDate(String dateString) {    
    String format="yyyy-MM-dd";
    LocalDateTime dateTime = LocalDateTime.parse(dateString);
    String dateCreated = dateTime.toString(format);
    Date date = dateTime.toDate();
    return date;
}

//Here is the comparator I am using for the binary search 
private static class DateComparator implements Comparator<Date> {
    private String format="yyyy-MM-dd";

    @Override
    public int compare(Date d1,Date d2){    
        LocalDateTime dt1 = new LocalDateTime(d1);
        LocalDateTime dt2 = new LocalDateTime(d2);    
        return dt1.toString(this.format).compareTo(dt2.toString(this.format));
    }
}

What I'm using works but Im afraid it might take up a lot of resources and time as well when comparing a large list of dates. Is there an inbuilt way to do this with JodaTime? Thank you.


Answer:

Your code can be reduced to:

List<LocalDate> dates = new ArrayList<>();
dates.add(LocalDateTime.parse("2016-08-18T05:18:24").toLocalDate());
dates.add(LocalDateTime.parse("2016-08-17T05:18:24").toLocalDate());
dates.add(LocalDateTime.parse("2016-08-19T17:00:24").toLocalDate());

System.out.println(dates.stream().anyMatch(LocalDate.now()::equals));

Which actually uses the JodaTime LocalDate instead of java.util.Date.

It does not print the index, but, as you said, you only want to check for existence.

Question:

I've been looking everywhere for a solution but can't manage to find one that works.

I have a "Scoreboard" that needs to show the highest "times" (period between two instants) the app has calculated with Joda Time.

All the strings are stocked in an ArrayList and displayed through an ArrayAdapter and a ListView.

The problem : Collections.sort doesn't seem to work properly even with ISO format.

i'm saving the time using the format :

PeriodFormatter formatter = ISOPeriodFormat.standard();

Which gives out this : "PT1M15.664S" (1 min 15seconds)

That i convert to a string and store into the ArrayList.

How can i sort these strings so it goes from the longest to the shortest amount of time in my Scoreboard ?

I've tried natural sorting and Alphanum Comparator with no luck. Every time it passes a cap (minutes, hours, days) the values get like this :

"PT2.455S"
"PT1.324S"
"PT1M15.333S"

Instead of what i would like :

"PT1M15.333S"
"PT2.455S"
"PT1.324S"

Using Collection.sort(myArrayList) doesn't work either.

Any idea what i should do ?

My code :

 // set is a set<String> retrieving it's values from a stringset scores saved
in the sharedpreferences of the app

 set = sharedPreferences.getStringSet("scores", null);

 //scores is the ArrayList
 scores.clear();


  if (set != null){

      scores.addAll(set);

  }else{

      scores.add("No Time Yet!");
      set = new LinkedHashSet<String>();
      set.addAll(scores);
      sharedPreferences.edit().putStringSet("scores",set).apply();
  }

//removing the String No Time Yet because it no longer serves a purpose here
  if ((set != null)&& (set.size()>1)){
      scores.remove("No Time Yet!");
  }


    arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,scores);

listView.setAdapter(arrayAdapter);

Collections.sort(scores);

Thank you for you time.


Answer:

Short answer: Use the class Duration, not Period.

Explanation:

Your general approach using the class Period is wrong. This type represents a tuple of various amount-unit-pairs. Some of them are not convertible or comparable. For example, it is impossible to determine if P30D is greater or equal to or smaller than P1M (think of February, April or August). So it is pretty clear why you cannot sort by periods resp. why this class does not implement the interface Comparable. And this objection is valid for the objects of type Period as well as for its canonical ISO-representation (as String).

But since you want

the highest "times" (period between two instants)

you can use Duration to determine the absolute amount of elapsed seconds and milliseconds between two given instants. This type is comparable and only has two minor constraints which are probably not important for you:

  • precision limited to milliseconds
  • ignores leap seconds

I recommend to compare duration objects, not strings because you want a chronological order, not a lexicographical order. So you could use the String-representation of Duration (like PT72.345S) for storage but parse it for comparison:

Instant i1 = new Instant(0);
Instant i2 = new Instant(72_345);
Duration d1 = new Duration(i1, i2);

Instant i3 = new Instant(60_000);
Instant i4 = new Instant(200_710);
Duration d2 = new Duration(i3, i4);

List<String> scoreTimes = new ArrayList<>();
scoreTimes.add(d1.toString());
scoreTimes.add(d2.toString());

// order from longest times to shortest times
Collections.sort(
    scoreTimes,
    new Comparator<String>() {

        @Override
        public int compare(String s1, String s2) {
            return Duration.parse(s2).compareTo(Duration.parse(s1));
        }
    }
);

System.out.println(scoreTimes); // [PT140.710S, PT72.345S]

Question:

lets say we have a DateTime ArrayList that contains a full date formatted yyyyMMddHHmmss

ArrayList<DateTime> dt = new ArrayList<DateTime>();
dt.add("20160418220000");
dt.add("20160418213000");
dt.add("20160418210000");
dt.add("20160418203000");

How do I print only the sharp hours (like 22:00) in joda-time?


Answer:

You can use the property of field hourOfDay to apply a floor-manipulation:

List<DateTime> dtListOld = dt; // your input
List<DateTime> dtListNew = new ArrayList<>();

for (DateTime dateTime : dtListOld) {
  dtListNew.add(dateTime.hourOfDay().roundFloorCopy());
}

These lists hold DateTime-objects according to your comment above. For further processing like formatting, you can use DateTimeFormatter. For comparisons with other unrounded instances of DateTime, you can use the usual comparing methods like isEqual() (strict test for same instant at sharp hours).

Please be aware of the fact that testing for strict equality of date-times (instants) at sharp hours can be errorprone if the source of date-time-objects is a clock (which usually produces millisecond-fractions). In that case, you could apply a similar rounding mode to the other objects to be compared to (but maybe on minute or second base).

Comparison example:

DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyyMMddHHmmss");
DateTime now = DateTime.now();
DateTime other1 = dtf.parseDateTime("20160418184137");
DateTime other2 = dtf.parseDateTime("20160418180000");

DateTime sharpHour = now.hourOfDay().roundFloorCopy();

if (!sharpHour.isEqual(other1.minuteOfDay().roundFloorCopy())) {
    System.out.println("Not matching sharp hour: " + other1);
}
DateTime other2Floor = other2.minuteOfDay().roundFloorCopy();
if (sharpHour.isEqual(other2Floor)) {
    System.out.println("Matching sharp hour: " + other2);
}

Output:

Not matching sharp hour: 2016-04-18T18:41:37.000+02:00

Matching sharp hour: 2016-04-18T18:00:00.000+02:00

The usage of floored rounding makes sure that you don't forget the parts whose precision is higher than needed. For example, a query/condition like getMinuteOfHour() == 0 would not take into account possible seconds or milliseconds deviating from zero.

Question:


Answer:

List<Date> date = new ArrayList<Date>();
date.add(new Date());

ez

or

date.add(user.getDate());