1. Overview

In this quick tutorial, we’ll learn how to convert between java.time.LocalDate and java.sql.Date.

2. Direct Conversion

To convert from LocalDate to java.sql.Date, we can simply use the valueOf() method available in java.sql.Date. Likewise, to convert the current date, we can use:

Date date = Date.valueOf(LocalDate.now());

Or, any other specific date:

Date date = Date.valueOf(LocalDate.of(2019, 01, 10));

Moreover, valueOf() throws NullPointerException in case of a null argument.

Now, let’s convert from java.sql.Date to LocalDate. For that, we can use the toLocalDate() method:

LocalDate localDate = Date.valueOf("2019-01-10").toLocalDate();

3. Using an AttributeConverter

First, let’s understand the problem.

Java 8 has lots of useful features, including the Date/Time API.

However, using it with some databases or persistence frameworks requires a bit more work than expected. For instance, JPA will map the LocalDate property into a blob instead of the java.sql.Date object. As a result, the database won’t recognize the LocalDate property as a Date type.

In general, we don’t want to perform an explicit conversion between the LocalDate and Date.

For example, suppose we have an entity object with a LocalDate field. When persisting this entity, we need to tell the persistence context how to map the LocalDate into the java.sql.Date.

Let’s apply a simple solution by creating an AttributeConverter class:

@Converter(autoApply = true)
public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDate localDate) {
        return Optional.ofNullable(localDate)
          .map(Date::valueOf)
          .orElse(null);
    }

    @Override
    public LocalDate convertToEntityAttribute(Date date) {
        return Optional.ofNullable(date)
          .map(Date::toLocalDate)
          .orElse(null);
    }
}

As we can see, the AttributeConverter interface accepts two types: LocalDate and Date in our case.

In short, the convertToDatabaseColumn() and convertToEntityAttribute()  methods will take care of the conversion process. We use Optional to easily handle possible null references inside the implementations.

Moreover, we’re also using the @Converter annotation. With the autoApply=true property, the converter will be applied to all mapped attributes of the entity’s type.

4. Convert LocalDateTime to java.sql.Date

Typically, java.sql.Date denotes a date without the time component, it keeps only the day, month, and year values, unlike LocalDateTime which also holds the time portion information such as hours, minutes, and seconds.

In short, there is no direct correlation between LocalDateTime and java.sql.Date. However, there is a relation between LocalDate and java.sql.Date as we explained earlier. With that being said, we need first to convert LocalDateTime to LocalDate to perform the conversion to java.sql.Date.

So, let’s add a test case to exemplify how to convert LocalDateTime to java.sql.Date:

@Test
void givenALocalDateTime_whenConvertingToSqlDate_thenReturnSqlDateWithoutTime() {
    LocalDateTime givenLocalDateTime = LocalDateTime.parse("2024-05-06T14:02:22.214");
    java.sql.Date expectedSqlDate = java.sql.Date.valueOf("2024-05-06");

    java.sql.Date sqlDate = java.sql.Date.valueOf(givenLocalDateTime.toLocalDate());

    assertThat(sqlDate).isEqualTo(expectedSqlDate);
}

Here, we converted the given LocalDateTime to LocalDate with the help of the toLocalDate() method. Then, we used the previous method valueOf() to pass from LocalDate to java.sql.Date. Notably, the time part of the LocalDateTime is lost when converting it to java.sql.Date.

5. Conclusion

In this quick tutorial, we showed two ways to convert between java.time.LocalDate and java.sql.Date. Moreover, we presented examples using direct conversion and using a custom AttributeConverter class. Finally, we illustrated how to convert LocalDateTime to java.sql.Date.

As usual, the complete code for this article is available over on GitHub.


« 上一篇: Java周报,264