我正在尝试将数据库中的餐厅预订日期存储在数据库中,但是,即使我提交的日期是正确的,休眠状态也会在数据库中存储我提交日期之前一天的日期。我不知道为什么...这可能是时区问题,但我不明白为什么...日期不应该受时区影响。
这是我的spring boot属性文件:
spring:
thymeleaf:
mode: HTML5
encoding: UTF-8
cache: false
jpa:
database: MYSQL
hibernate:
ddl-auto: update
properties:
hibernate:
locationId:
new_generator_mappings: false
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
jdbc:
time_zone: UTC
datasource:
driver:
class: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/databaseName?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: username
password: **********
我来自意大利,所以我的时区是这样:
当前我们是UTC + 2h。
我要存储的对象就是这个:
@Entity
public class Dinner {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long dinnerId;
private LocalDate date;
...
我用来拦截POST请求的控制器是这样的:
@PreAuthorize("hasRole('USER')")
@PostMapping
public String createDinner(@RequestParam(value="dinnerDate") String dinnerDate, Principal principal, Model model){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(dinnerDate, formatter);
dinnerService.createDinner(date);
return "redirect:/dinners?dinnerDate=" + dinnerDate;
}
哪个调用服务方法 createDinner ,该方法调用Jpa方法 save 来存储对象。 我正在使用百里香处理html模板。 如果我在数据库中提交日期30/6/2019,则会得到29/6/2019。当我按日期检索Dinner对象时,如果插入30/6/2019,则会得到日期为29/6/2019的Dinner。因此,似乎Spring自己以一种奇怪的方式来处理日期...考虑某种时区,但我不知道如何禁用或处理它。有想法吗?
答案 0 :(得分:0)
相同的问题(和相同的国家!:-))。
我怀疑如果在保留日期后将休眠或jpa设置为时区UTC
,而将机器设置为默认时区== Europe/Rome
,那么它将自动从机器时区转换到数据库时区,如果您将所有日期都以UTC格式存储在数据库中,那么这不是一个坏功能。
当您在保留日期之前转换日期时,就会发生问题:它被转换了两次。至少这是我的情况。
仍在寻找最佳解决方案!以防万一,然后再将其添加到答案中。
答案 1 :(得分:0)
您不需要为模式yyyy-MM-dd
定义格式。 LocalDate#parse默认使用DateTimeFormatter.ISO_LOCAL_DATE
,这意味着LocalDate.parse("2020-06-29")
无需显式应用格式即可工作。
由于您已经知道时区中的日期时间与UTC中的日期时间不同,因此您不应该仅考虑日期。相反,您应该同时考虑日期和时间,例如2020-06-29在UTC的11:30 PM将在您所在的时区于2020-06-30降落。因此,您应该做的第一件事就是将数据库中字段的类型更改为TIMESTAMP
。
将字段类型更改为TIMESTAMP
后,请按以下方式更改方法createDinner
:
LocalDateTime dinnerDateTime = LocalDateTime.of(LocalDate.parse(dinnerDate), LocalTime.of(0, 0, 0, 0));
OffsetDateTime odt = dinnerDateTime.atOffset(ZoneOffset.UTC);
dinnerService.createDinner(odt);
然后在DinnerService
(或DinnerServiceDAO
内部,无论您编写了在数据库中插入/更新记录的逻辑):
pst.setObject(index, odt);
其中pst
代表PreparedStatement
的对象,而index
代表插入/更新查询中此字段的索引(从1
开始)。
答案 2 :(得分:-1)
您必须像这样设置serverTimezone变量:
url:jdbc:mysql:// localhost:3306 / databaseName?useSSL = false&useUnicode = true&useJDBCCompliantTimezoneShift = true&useLegacyDatetimeCode = false&serverTimezone = Europe / Italy