0

I'm receiving this timestamp in a json body:

{
  "timestamp": "2019-03-27 10:04:01.446937+01"
}

And I would like to convert this timestamp into europe/brussels timezone.

I'm using com.fasterxml.jackson.core so I'm wondering if this is possible with annotations in this class for example.

public class MyClass {

    @JsonFormat(...)
    Date timestamp;
}

If not how can this be achieved using plain java code?

bob
  • 198
  • 1
  • 10
  • 2
    I strongly recommend you don’t use `Date`. That class is poorly designed and long outdated. Instead use `OffsetDateTime` or `ZonedDateTime`. Both are from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). Or may just consider `Instant` from the same API. – Ole V.V. Aug 25 '22 at 04:44
  • 2
    Also a `Date` never could hold a time zone, so wanting to convert it to Europe/Brussels time zone does not make sense. – Ole V.V. Aug 25 '22 at 05:02

3 Answers3

2

ISO 8601

If possible, educate the publisher of your data about using standard ISO 8601 formats when exchanging date-time values textually. That means:

  • Using a T in the middle instead of a SPACE character.
  • Using hours with minutes in the offset, delimited by a COLON character, rather than abbreviating.

DateTimeFormatter

If switching to ISO 8601 is not possible, define a formatting pattern to match your input.

String input = "2019-03-27 10:04:01.446937+01" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSSSSSx" ) ; 

java.time.OffsetDateTime

Parse as an OffsetDateTime.

OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;

odt.toString(): 2019-03-27T10:04:01.446937+01:00

ZonedDateTime

Apply your desired time zone.

ZoneId z = ZoneId.of( "Europe/Brussels" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ; 

See this code run at Ideone.com.

zdt.toString(): 2019-03-27T10:04:01.446937+01:00[Europe/Brussels]

In this particular case, Brussels time is already using an offset of one hour ahead of UTC. So no change for the time-of-day from our original.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Extracts the "timestamp" field in the JSON object as String. Then use the java.text.SimpleDateFormat with the correct formatter to parse the string into java.util.Date object. Then change to the required timezone before displayed it back into JSON string.

Minh Kieu
  • 475
  • 3
  • 9
  • 1
    No, please don’t, please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. We have so much better in [`java.time`, the modern Java date and time API,](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. Yes, you can use it on Android. For older Android look into [desugaring](https://developer.android.com/studio/write/java8-support-table). – Ole V.V. Aug 25 '22 at 04:45
  • @OleV.V. There was no mentioned of old ways or new APIs. What I said was only a concept. There is no code posted. And does your modern API works in a dated JDK1.8? I guess some answers are suggestive whereas your solutions dictated. Time of grow up??? – Minh Kieu Aug 25 '22 at 09:38
  • 1
    @MinhKieu Yes, the *java.time* classes are built into Java 8. Sun, Oracle, and the JCP community all gave up on those terrible legacy date-time classes with the unanimous adoption of JSR 310 years ago. I suggest you do the same. – Basil Bourque Aug 25 '22 at 09:47
  • Any programmer is free to do whatever foolishness they can, I am dictating nothing. The Java community has unanimously decided on preferring java.time. – Ole V.V. Aug 25 '22 at 09:51
0

Here's the plain Java solution. I guess there's more elegant way for this.

static {
    // make sure your JVM's timezone won't be "combined" with the input's timezone.
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}

public class DateHandler extends StdDeserializer<Date> {
    public DateHandler() {
        this(null);
    }

    public DateHandler(Class<?> clazz) {
        super(clazz);
    }

    @Override
    public Date deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
        String date = jsonParser.getText();
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSZ"); // or DateTimeFormatter.ISO_OFFSET_DATE_TIME
            return sdf.parse(date+"00");
        } catch (Exception e) {
            log.error(e, e);
            return null; // TODO throw new JsonParseException..
        }
    }
}

and instead of your @JsonFormat(...) do @JsonDeserialize(using = DateHandler.class)

Now new ObjectMapper().readValue("{ \"timestamp\": \"2019-03-27 10:04:01.446937+01\"}", MyClass.class) returns a date with +0100 offset as required.

ShaharT
  • 442
  • 5
  • 13
  • 1
    You are using terrible date-time classes that are now legacy, supplanted years ago by the modern *java.time* classes. – Basil Bourque Aug 25 '22 at 02:04
  • 1
    That is (1) setting the JVM default time zone with consequences for the rest of your program and all other programs running in the same JVM, which can have consequences you can’t know. (2) Giving the wrong result. Furthermore I strongly recommend you don’t use `TimeZone`, `Date` and `SimpleDateFormat`. Those classes are poorly designed and long outdated, the last one in particular notoriously troublesome. Instead use [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Aug 25 '22 at 04:48