How to compare/find a list of XMLGregorianCalendar dates

1.3k Views Asked by At

For eg: we have a List<XMLGregorianCalendar> dates we need to find the latest date in this list.

Really appreciate your help!

2

There are 2 best solutions below

3
Michael Kay On

Rather strangely, XMLGregorianCalendar has a compareTo() method but does not implement Comparable, which makes this unnecessarily difficult. I'd be inclined to convert your values to something more Java-friendly like a ZonedDateTime and work with that. I guess if you're using XMLGregorianCalendar then it's probably because you're using JAXB data binding to XML: the class was invented because at the time, none of the Java date/time options quite matched the XSD data types, but that's no longer really the case.

0
Anonymous On

As Michael Kay said in a comment, in practice date-times in a list usually all have time of day or none of them, and all have UTC offset (“timezone” in the XML parlance) or none. And this is a requirement for your request to make sense. Which of 23:34:45 and 2021-03-31 is later? XMLGregorianCalendar is flexible enough to accommodate both.

If your XMLGregorianCalendar objects all have full dates, times and offset, I suggest sorting them as OffsetDateTimes:

    DatatypeFactory factory = DatatypeFactory.newInstance();
    List<XMLGregorianCalendar> dates = Arrays.asList(
            factory.newXMLGregorianCalendar(
                    2021, DatatypeConstants.MARCH, 30, 12, 0, 0, 0, 0),
            factory.newXMLGregorianCalendar(
                    2021, DatatypeConstants.MARCH, 30, 9, 0, 0, 0, 60),
            factory.newXMLGregorianCalendar(
                    2021, DatatypeConstants.MARCH, 30, 13, 0, 0, 0, 60));
    
    if (dates.isEmpty()) {
        System.out.println("No dates");
    } else {
        XMLGregorianCalendar maxDate
                = Collections.max(dates,
                        Comparator.comparing(xgc -> OffsetDateTime.parse(xgc.toString())));
        System.out.println(maxDate );
    }

Output from this snippet is:

2021-03-30T13:00:00.000+01:00

I have chosen my data so that the first and the last item in the list denote the same point in time, only one is on UTC, the other at offset +01:00 (for example Irish Summer Time). That the latter is output is no coincidence. OffsetDateTime.compareTo() sorts first by point in time (instant in java.time parlance), next by local date-time, and since 13 sounds later than 12, this is chosen.

There are more ways to convert from XMLGregorianCalendar to OffsetDateTime. I chose parsing as string because it gives us validation that the XMLGregorianCalendar has all of date, time and offset.

If date is to be taken literally, your objects represent only dates, instead use LocalDate. The code is almost the same:

    List<XMLGregorianCalendar> dates = Arrays.asList(
            factory.newXMLGregorianCalendarDate(2021, DatatypeConstants.MARCH, 26,
                    DatatypeConstants.FIELD_UNDEFINED),
            factory.newXMLGregorianCalendarDate(2021, DatatypeConstants.MARCH, 29,
                    DatatypeConstants.FIELD_UNDEFINED),
            factory.newXMLGregorianCalendarDate(2021, DatatypeConstants.MARCH, 28,
                    DatatypeConstants.FIELD_UNDEFINED));
    
    if (dates.isEmpty()) {
        System.out.println("No dates");
    } else {
        XMLGregorianCalendar maxDate
                = Collections.max(dates,
                        Comparator.comparing(xgc -> LocalDate.parse(xgc.toString())));
        System.out.println(maxDate );
    }

2021-03-29

If you have got dates and times but no offsets, use LocalDateTime in the same way.