【问题标题】:Why postgres saves date in different ways?为什么 postgres 以不同的方式保存日期?
【发布时间】:2020-07-28 13:58:04
【问题描述】:

我有带有 PostgreSQL 的 Spring Boot 应用程序。当我保存像 2020-07-28 × 17:30:00 这样的日期时,在 PostgreSQL 中它看起来是 2020-07-28 × 06:30:00。有时差是 12 小时有时是 11。在前端它以正确的方式出现,但是当我在 cvs 中导出它时,错误的日期就出来了。为什么会发生以及如何解决? 这些是我的变量:

    @NotNull
    @DateTimeFormat(pattern = "dd/mm/yyyy")
    private Date startDate;

    @DateTimeFormat(pattern = "dd/mm/yyyy")
    private Date endDate;

【问题讨论】:

  • 你为什么首先使用 java.util.Date?
  • 2020-07-28 в 17:30:00 不是date 值,而是timestamp。在你的 Java 代码中应该是 java.time.LocalDateTime(或者更好:java.time.OffsetDateTime
  • 你的 JVM 默认时区是什么?你的专栏是什么类型的?问题很可能是 PostgreSQL 标准化为 UTC 或类似的东西。

标签: java spring spring-boot date


【解决方案1】:

说实话,java.util.Date 很烦人。如果你想在数据库中或前面使用它,你应该更好地使用 LocalDateTime 。但是,如果您想继续使用 java.util.Date,我找到了一种对我有用但几乎只是绕过问题的方法。如果您愿意,可以尝试这样使用它:

 Date startDate;
 SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 System.Out.println(formater.format(startDate));

我用它来插入数据库和前端,对我来说效果很好

【讨论】:

【解决方案2】:

避免Date

切勿使用java.util.Datejava.sql.Date 类。与CalendarSimpleDateFormat 一起,这些现在是遗留的,多年前被现代的java.time 类所取代。

java.time 使用 JDBC 4.2+ 的类

如果您要记录时间线上的特定时间点,请使用:

  • 在 Postgres 中,TIMESTAMP WITH TIME ZONE 类型的列。注意WITH 而不是WITHOUT(不能代表片刻)。
  • 在 Java 中,InstantOffsetDateTimeZonedDateTime

JDBC 4.2 及更高版本允许我们与数据库交换 java.time 对象。但奇怪的是,JDBC 4.2 只需要支持OffsetDateTime,而不需要支持这两种更常用的类型。幸运的是,转换很容易。

LocalDate ld = LocalDate.of(  2020 , Month.JULY , 28 ) ;
LocalTime lt = LocalTime.of( 17 , 30 ) ;
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

可能能够将其传递给您的特定 JDBC 驱动程序。

myPreparedStatement.setObject( … , zdt ) ;

如果不是,请转换为OffsetDateTime

myPreparedStatement.setObject( … , zdt.toOffsetDateTime() ) ;

检索。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

调整到您想要的时区。

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant​( z ) ;

以文本形式呈现给用户,已本地化。

Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( f ) ;

在 UTC 中查看同一时刻。根据定义,Instant 对象始终采用 UTC。

Instant instant = zdt.toInstant() ;

使用此处看到的代码将消除您对时区的意外。

所有这些都已经在 Stack Overflow 上进行了很多次介绍。所以我很简短。搜索以了解更多信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-07
    • 2013-08-25
    • 2020-02-18
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多