0

I'm having trouble to figure out what is this date format: 2019-02-28T12:17:46.279+0000. I have tried different date formats to get this result but nothing worked. Closest pattern was: yyyy-MM-dd'T'HH:mm:ss.SSSZ But with this pattern output was like this: 2019-02-28T12:17:46.279-0000 (- is after seconds instead of +)

I get this exception:

Caused by: java.lang.IllegalArgumentException: 2019-02-28T12:17:46.279+0000
    at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl$Parser.skip(XMLGregorianCalendarImpl.java:2932)
    at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl$Parser.parse(XMLGregorianCalendarImpl.java:2898)
    at org.apache.xerces.jaxp.datatype.XMLGregorianCalendarImpl.<init>(XMLGregorianCalendarImpl.java:478)
    at org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl.newXMLGregorianCalendar(DatatypeFactoryImpl.java:230)
    at __redirected.__DatatypeFactory.newXMLGregorianCalendar(__DatatypeFactory.java:132)
    at javax.xml.bind.DatatypeConverterImpl.parseDate(DatatypeConverterImpl.java:519)
    at javax.xml.bind.DatatypeConverter.parseDate(DatatypeConverter.java:431)
    at eu.europa.ec.my.custom.package.model.mapper.XsdDateTimeConverter.unmarshal(XsdDateTimeConverter.java:23)

My XsdDateTimeConverter class looks like this:

public class XsdDateTimeConverter {

    public static Date unmarshal(String dateTime) {
        return DatatypeConverter.parseDate(dateTime).getTime();
    }

    public static String marshalDate(Date date) {
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return DatatypeConverter.printDate(calendar);
    }

    public static String marshalDateTime(Date dateTime) {
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateTime);
        return DatatypeConverter.printDateTime(calendar);
    }
}

And parsed date in my postgres db looks like this:

move_timestamp timestamp(6) with time zone

2019-02-28 12:17:46.279+00

In my rest method I use ObjectMapper like this.

MyCustomResponseDto responseDto = customService.getCustomResponseDto(query);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
String strValue = mapper.writeValueAsString(responseDto);
return Response.ok(strValue).build();

I guess what I really wanted is what is the right pattern for this date. I can go in this page: http://www.sdfonlinetester.info/ and enter my pattern (e.g. yyyy-MM-dd'T'HH:mm:ss.SSSZ) and it gives you an actual date output for that pattern. I need the other way around. I want to enter my date and it will give me the right pattern for it.

gozluklu_marti
  • 79
  • 1
  • 7
  • 26
  • 1
    What I don’t understand is why you want to marshal from and to `Date`. The `Date` class is poorly designed and long outdated. It seems that `OffsetDateTime` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) would have been a better and more natural choice. Anyway a wild guess: since your string has time of day in it, maybe you should use `DatatypeConverter.parseDateTime`? – Ole V.V. Feb 28 '19 at 13:14
  • @OleV.V. Ihave tried to use `DatatypeConverter.parseDateTime` and the result was the same. I wish I could use OffsetDateTime but there are other modules depend on Date object. So, I can't replace it for now. – gozluklu_marti Feb 28 '19 at 13:22

3 Answers3

2

tl;dr

OffsetDateTime.parse( 
    "2019-02-28T12:17:46.279+0000" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" , Locale.ROOT )
)

java.time

You are using terrible Calendar class that was supplanted years ago by the java.time classes.

ISO 8601

Your input string is in standard ISO 8601 format, designed for human-readable machine-parseable textual representations of date-time values. That is a good thing.

The java.time classes use ISO 8601 formats by default when parsing/generating strings.

OffsetDateTime

You should be able to simply parse with OffsetDateTime.

OffsetDateTime.parse( "2019-02-28T12:17:46.279+0000" )

…but unfortunately the optional COLON character being omitted from the offset (+00:00) is a problem. The OffsetDateTime class has a minor bug where it refuses to parse without that character. The bug is discussed here and here.

The ISO 8601 standard permits the colon’s absence, but practically you should always include it. The OffsetDateTime class is not alone; I have seen other libraries that break when the colon or padding zeros are absent. I suggest asking the publisher of your data to use the full ISO 8601 format including the colon.

The workaround for the OffsetDateTime bug is to define a DateTimeFormatter explicitly.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" , Locale.ROOT ) ;

Then parse.

String input = "2019-02-28T12:17:46.279+0000" ;
OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;

To generate text in full standard ISO 8601 format, simply call toString.

String output = odt.toString() ;

See this code run live at IdeOne.com.

output: 2019-02-28T12:17:46.279Z

The Z on the end means UTC, that is +0000 or +00:00. Pronounced “Zulu”. Very commonly used, more immediately readable than the numeric offset.

If you want same output format as your input, use the same DateTimeFormatter.

String output = odt.format( f ) ;
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

You may try below code

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ENGLISH); String lastmod = format.format(new Date());

charan
  • 149
  • 5
  • Locale.ENGLISH it may changed based on your requirements – charan Feb 28 '19 at 13:27
  • As I wrote in my question as well this pattern `yyyy-MM-dd'T'HH:mm:ss.SSSZ` is not match for output date in the exception. But fyi, I already tried this approch without success. – gozluklu_marti Feb 28 '19 at 13:45
0

Save yourself a mountain of trouble and save the epochtime in millis. Only parse and render dates in UIs. Very very few cases of scheduling for humans require a computer to know hours, day, week, month, year... But saving an instant in time is just a 'long'.

user2023577
  • 1,752
  • 1
  • 12
  • 23
  • I wish I could do what you suggesting but this is a complex system with lots of integrations. I can't just change the structure of the project. I just need to make this work for now :) – gozluklu_marti Feb 28 '19 at 14:35
  • Unfortunately, the meaning of a count of milliseconds cannot be discerned by human reading. So debugging and logging are complicated and error-prone. The [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) formats were designed for this very purpose, exchanging date-time values as text that is easy to parse by machine as well as easy to read by humans across cultures. – Basil Bourque Feb 28 '19 at 20:00
  • debugging: use an IDE formatter, logging: n/a for persistence/protocol, and you can log a rendered date from millis at will. 2 computers exchanging should NEVER have to use a rendered timestamp, THAT is slow and error prone. Resorting to evil strings and parsing is just repeating bad decision like those of the fools who invented xml and http, which everyone is fighting hard to eliminate still today. – user2023577 Mar 01 '19 at 00:12