Arun Kumar
Arun Kumar

Reputation: 6794

java.time.LocalDateTime conversion issue if seconds are 00

My web application is using Apache CXF and JAVA8, and facing below error in response if user send xs:datetime input(seconds 00) as

<urn1:dateTimeVal>2016-04-29T20:00:00</urn1:dateTimeVal>

ERROR :

org.apache.cxf.interceptor.Fault: Marshalling Error: cvc-datatype-valid.1.2.1: '2016-04-29T20:00' is not a valid value for 'dateTime'.

I debug and analysed that if user send dateTimeVal as 2016-04-29T20:00:00 then CXF validations for input are passed and XML value is UnMarshaled to java.time.LocalDateTime as 2016-05-05T20:00 , and at the time of returning the response, the Marshaling error occurs due to loss of seconds part(00).

Any help/hint are appreciated.

P.S : You can try with below snippet :

   java.time.LocalDateTime dt= java.time.LocalDateTime.of(2016, Month.MAY, 5, 20, 00, 00);
   System.out.println(dt);

Note : Above code sample is just for understanding to print datetime value. But actual return type expected in web application is java.time.LocalDateTime

OUTPUT EXPECTED : 2016-05-05T20:00:00

OUTPUT ACTUAL : 2016-05-05T20:00

EDIT : The binding (JAXB) content for the field is :

 @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
    @XmlSchemaType(name = "dateTime")
    @Generated(value = "com.sun.tools.xjc.Driver", date = "2016-05-03T05:28:57+05:30", comments = "JAXB RI v2.2.11")
    @NotNull
    protected LocalDateTime dateTimeVal;

AND LocalDateTimeAdapter File is

 import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeParseException;
    import java.time.temporal.TemporalAccessor;
    import javax.xml.bind.annotation.adapters.XmlAdapter;

    public class LocalDateTimeAdapter
      extends XmlAdapter<String, LocalDateTime>
    {
      public static LocalDateTime parse(String value)
      {
        DateTimeFormatter dateTimeAndZoneformatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
        DateTimeFormatter dateTimeformatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        TemporalAccessor ta = null;
        try
        {
          ta = dateTimeformatter.parse(value);
        }
        catch (DateTimeParseException ex)
        {
          ta = dateTimeAndZoneformatter.parse(value);
        }
        return LocalDateTime.from(ta);
      }

      public static String print(LocalDateTime value)
      {
        return value.toString();
      }

      public LocalDateTime unmarshal(String value)
      {
        return parse(value);
      }

      public String marshal(LocalDateTime value)
      {
        return print(value);
      }
    }

Upvotes: 11

Views: 7511

Answers (2)

Hank D
Hank D

Reputation: 6471

The problem appears to be in LocalDateTimeAdapter.print(). LocalDateTime.toString() omits the seconds when the seconds value is 0.

If you change it to

public static String print(LocalDateTime value)
{
    return value.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}

it will provide the seconds as well when marshaling.

To see a quick example, note the results of the following snippet:

System.out.println(LocalDateTime.of(2016,1,1,0,0,0,0).toString());
System.out.println(LocalDateTime.of(2016,1,1,0,0,0,0).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

The output it gives is

2016-01-01T00:00
2016-01-01T00:00:00

In the documentation for LocalDateTime.toString() it explains this behavior:

The output will be one of the following ISO-8601 formats:
- uuuu-MM-dd'T'HH:mm
- uuuu-MM-dd'T'HH:mm:ss
- uuuu-MM-dd'T'HH:mm:ss.SSS
- uuuu-MM-dd'T'HH:mm:ss.SSSSSS
- uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS
The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.

Upvotes: 8

Philip Helger
Philip Helger

Reputation: 1864

You may want to use

System.out.println (DateTimeFormatter.ISO_LOCAL_DATE_TIME.format (dt));

It gives:

2016-05-05T20:00:00

Upvotes: 4

Related Questions