【问题标题】:How to stop LocalDate from changing when being saved to a mySQL database保存到 mySQL 数据库时如何阻止 LocalDate 更改
【发布时间】:2018-03-08 20:47:38
【问题描述】:

使用 JPA CriteriaBuilder API 将 LocalDate 字段(例如“2017-09-27”)保存到 mySQL Date 列时,结果不同(例如“2017-09-26”)。

我已使用 SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP) 验证我的数据库的时区设置为 UTC,因为结果是 '00:00:00'。

我在本地对此进行测试,并且我的时区为 GMT + 2,所以我怀疑当从 ​​LocalDate 转换到 Date 时,会扣除 2 小时并在日期前 1 天生成日期请求的日期(假设 LocalDate 字段,由于它没有没有时间信息,被视为 00:00:00。

在这种情况下保存 LocalDates 的最佳方法是什么?我是否应该遵循https://stackoverflow.com/a/29751575/3832047 此处的建议并将所有 LocalDate 字段明确设置为 UTC 或类似的东西?

我进行了测试,看看在代码中转换它们时会发生什么,并得到以下结果:

Date convertedDate = Date.valueOf(localDate);

conversion-result

编辑

这是我用来检索数据的代码示例,其中也发生了奇数日期更改。如果我请求2017-06-27 的数据,我会收到2017-06-26 的结果。

CriteriaBuilder criteriaBuilder = sessionFactory.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(HorseAndTrailerRequest.class);
Root<HorseAndTrailerRequest> criteria = criteriaQuery.from(HorseAndTrailerRequest.class);

ParameterExpression<LocalDate> effectiveDateParameter = criteriaBuilder.parameter(LocalDate.class);
    criteriaQuery.select(criteria)
            .where(
                    criteriaBuilder.equal(criteria.get("effectiveDate"), effectiveDateParameter)
            );

TypedQuery<HorseAndTrailerRequest> query = sessionFactory.getCurrentSession().createQuery(criteriaQuery);
query.setParameter(effectiveDateParameter, date);
return query.getResultList();

【问题讨论】:

  • Java LocalDate 对象不存储时间或时区信息(请参阅Javadoc],我怀疑还有别的东西。
  • 您能否尝试运行以下命令来确认您的 MySQL 服务器时区:SELECT @@system_time_zone, NOW(), UTC_TIMESTAMP()
  • @TimBiegeleisen 结果是UTC | 2017-09-27 11:28:51 | 2017-09-27 11:28:51
  • 我赞成你的问题,但在这一点上,我认为我们需要查看将本地日期保存到 MySQL 中的 Java 代码。
  • 好的,谢谢,它也发生在读取上 - 当查询请求来自“2017-09-27”的数据时,我只接收来自“2017-09-26”的数据,非常奇怪的行为.我将通过阅读示例来编辑问题。

标签: mysql java-8 jpa-2.0 hibernate-5.x localdate


【解决方案1】:

由于LocalDate 没有TimeZone,您可以将column_date 映射到您的数据库架构中,并使用AttributeConverterLocalDate 转换为long 以避免时区转换问题:

import javax.persistence.Converter;
import java.time.LocalDate;
import javax.persistence.AttributeConverter;
@Converter
public class LocalDateToLong implements AttributeConverter<LocalDate, Long> {

    @Override
    public Long convertToDatabaseColumn(LocalDate date) {
        if (date != null) {
            long epochDay = date.toEpochDay();
            return epochDay;
        }
        return null;
    }

    @Override
    public LocalDate convertToEntityAttribute(Long epochDay) {
        // TODO Auto-generated method stub
        if (epochDay != null) {
            LocalDate date = LocalDate.ofEpochDay(epochDay);
            return date;
        }
        return null;
    }

}

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,我在看到 hibernate atlassian 问题时解决了它(这里是线程:https://hibernate.atlassian.net/browse/HHH-11396)。你有两种选择:

    1. 使用-Duser.timezone=Europe/Berlin 或通过TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin")); 以编程方式设置JVM

    2. 创建一个分区的 DateTime,然后将其转换回 Date

      public static final ZoneId ZONE_EUROPE_BERLIN = ZoneId.of("Europe/Berlin");
      
      @Override
      public Date convertToDatabaseColumn(LocalDate locDate) {
          if (locDate == null) {
              return null;
          }
      
          ZonedDateTime zonedDateTime = locDate.atStartOfDay(ZONE_EUROPE_BERLIN);
          LocalDate producerLocalDate = zonedDateTime.toLocalDate();
          Date date = Date.valueOf(producerLocalDate);
      
          return date;
      }
      

    我使用了第二种选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-08
      • 1970-01-01
      • 1970-01-01
      • 2012-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-24
      相关资源
      最近更新 更多