Converting Luxon DateTime ISO format to Java LocalDateTime

100 views Asked by At

My frontend vue application sends a luxon DateTime object to a Spring Boot backend which has a LocalDateTime field, however, java is unable to parse the DateTime object. I have tried using both luxon's toSQL() and toISO() methods to format, but of no avail.

What would be the optimal way of sending date time from a vue application to a java backend?

example request:

"date_deadline": "2024-03-07 14:54:51.440 +08:00"

The java entity looks as follows:

@Entity
@Table(name = "todos")
public class Todo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    private LocalDateTime date_created;
    @Column (name = "date_deadline")
    @Temporal(TemporalType.TIMESTAMP)
    private LocalDateTime date_deadline;
}

When passing the json in the request body, I get the following 400 response:

    "message": "JSON parse error: Cannot deserialize value of type `java.time.LocalDateTime` from String \"2024-03-07 14:54:51.440 +08:00\": Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text '2024-03-07 14:54:51.440 +08:00' could not be parsed at index 10",
3

There are 3 answers

0
Pablo Aragonés On

You are having this problem because the date format that Vue sends is not compatible with the format that LocalDateTime has in Java, which is ISO-8601 ("2024-03-07T14:54:51.440"). You can solve this in several ways:

  1. Change the date format in Vue:
import { DateTime } from 'luxon';

const luxonDateTime = DateTime.local(); // Replace this with your Luxon DateTime object
const isoDateTime = luxonDateTime.toISO(); // Format to ISO-8601 string
  1. Send the date as String. You can convert the date in Vue to a String with the ISO-8601 format and send it to the backend.

  2. Custom Deserialization in Spring Boot. You can modify the default deserializer to fit your format.

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS Z");

    @Override
    public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException {
        String dateTimeString = jsonParser.getText();
        return LocalDateTime.parse(dateTimeString, formatter);
    }
}

You can use it with the annotation @JsonDeserialize in your entity.

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@Entity
@Table(name = "todos")
public class Todo {
    // Other fields

    @Column(name = "date_deadline")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime dateDeadline;

    // Getters and setters
}
2
demiglace On

Solved this by removing the offset:

DateTime.now().toISO({ includeOffset: false })

2024-03-07T18:18:30.932

0
Basil Bourque On

tl;dr

Parse your non-standard input as OffsetDateTime object. Change your field declaration to match.

OffsetDateTime.parse( 
    "2024-03-07 14:54:51.440 +08:00" , 
    DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSS xxx" ) 
)
.toString()

2024-03-07T14:54:51.440+08:00

No, not LocalDateTime

Your input includes three parts: date, time, and offset-from-UTC.

A LocalDateTime, in contrast, has only two parts: date and time, but lacks the offset.

Type Date Time Offset Appropriate?
"2024-03-07 14:54:51.440 +08:00"
OffsetDateTime
LocalDateTime

OffsetDateTime

Change the type of your field to OffsetDateTime.

private OffsetDateTime date_deadline;

Instant

Alternatively, use Instant if you want to adjust values to an offset of zero. Generally best to use an offset of zero unless your business rules deem it important to remember the original offset.

No, not ISO 8601

Your input string is not in ISO 8601 format. In standard format, the middle SPACE should be a T, and the SPACE before the offset should be deleted. Example: 2024-03-07T14:54:51.440+08:00.

Ideally, you would educate the publisher of your data to use strictly compliant ISO 8601 formats only when exchanging date-time values textually.

DateTimeFormatter

The java.time classes built into Java 8 and later use standard ISO 8601 formats by default when parsing/generating text. So no formatting pattern need be defined.

For your non-standard inputs, we need to define a formatting pattern using DateTimeFormatter class.

String input = "2024-03-07 14:54:51.440 +08:00";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss.SSS xxx" );
OffsetDateTime odt = OffsetDateTime.parse( input , f );