Richard
Richard

Reputation: 8955

Java Date format : String to XMLGregorianCalendar

I have a String date I am converting to a XMLGregorianCalendar. The below code converts it with no errors. However, the system I pass the date to, gets the error reported below.

The following XMLGregorianCalendar works:

enter image description here

The following XMLGregorianCalendar does not work (the code below converts it to this):

enter image description here

Question

How do I convert the string to the required format?

 public static void main(String []args){
    try {
        String commenceTOString = "2021-06-30 05:00:00";
        java.util.Date dateCommence = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(commenceTOString);
        System.out.println(dateCommence);
        java.util.GregorianCalendar c = new java.util.GregorianCalendar();
        c.setTime(dateCommence);
        
        javax.xml.datatype.XMLGregorianCalendar commence = javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
        System.out.println(commence);

    } catch (Exception e) {
        e.printStackTrace();
    }
 }

Error

E: Message validation failed. Errors: [cvc-pattern-valid: Value '2021-06-30T06:30:00.000+02:00' is not facet-valid with respect to pattern '(((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-9])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-30)))|(((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((0[1,3-9])|(1[0-2]))-(29|30)))))T([0-1][0-9]|[2][0-3])(:([0-5][0-9])){1,2}' for type 'dateTime'.cvc-attribute.3: The value '2021-06-30T06:30:00.000+02:00' of attribute 'DepartureDateTime' on element 'FlightSegment' is not valid with respect to its type, 'dateTime'.]. http://www.elleipsis.com/booking/exception/35a8ac87-6743-4719-9504-a8a17a1a0471

Upvotes: 2

Views: 6255

Answers (2)

Anonymous
Anonymous

Reputation: 86369

There are many ways to do this. Generally I recommend that you use java.time for your date and time work, also when there is no direct conversion between java.time classes and XMLGregorianCalendar.

The hack

The hack is simply to edit the T into the string that XMLGregorianCalendar expects to be there and then parse the modified string directly. Then we neither need java.time nor Date nor SimpleDateFormat.

    String commenceTOString = "2021-06-30 05:00:00";
    XMLGregorianCalendar commence = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(commenceTOString.replace(' ', 'T'));
    System.out.println(commence);

Output:

2021-06-30T05:00:00

Convert via String

Parse into LocalDateTime, format into a string in the format XMLGregorianCalendar knows and let the DatatypeFactory parse again:

    DateTimeFormatter parser = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss");
    
    LocalDateTime dateTime = LocalDateTime.parse(commenceTOString, parser);
    XMLGregorianCalendar commence = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(dateTime.format(formatter));
    System.out.println(commence);

Output is the same as before.

Convert via numbers

Though a few lines longer this is the conceptually simple conversion: transfer each field from LocalDateTime to XMLGregorianCalendar.

    XMLGregorianCalendar commence = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(
                    dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), 
                    dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(),
                    DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
    System.out.println(commence);

Output is still the same.

Convert via GregorianCalendar

I believe that this is the official conversion: convert to ZonedDateTime to GregorianCalendar and finally to XMLGregorianCalendar. We need to set the unwanted field to FIELD_UNDEFINED just as in your own answer.

    ZonedDateTime dateTime = LocalDateTime.parse(commenceTOString, parser)
            .atZone(ZoneOffset.UTC);
    GregorianCalendar gc = GregorianCalendar.from(dateTime);
    XMLGregorianCalendar commence = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar(gc);
    commence.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
    commence.setMillisecond(DatatypeConstants.FIELD_UNDEFINED);
    System.out.println(commence);

Link

Oracle tutorial: Date Time explaining how to use java.time.

Upvotes: 1

Richard
Richard

Reputation: 8955

This fixed it for me: (using DatatypeConstants.FIELD_UNDEFINED)

           GregorianCalendar c = new GregorianCalendar();
            c.setTime(dateCommence);
            XMLGregorianCalendar commence = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
            commence.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
            commence.setMillisecond(DatatypeConstants.FIELD_UNDEFINED);

Upvotes: 0

Related Questions