英文:
Why postgres saves date in different ways?
问题
以下是翻译好的部分:
我有一个使用PostgreSQL的Spring Boot应用程序。当我保存类似于2020-07-28 в 17:30:00的日期时,在PostgreSQL中它显示为2020-07-28 в 06:30:00。有时差异是12小时,有时是11小时。在前端,它显示正确,但是当我将其导出为CSV时,会出现错误的日期。为什么会发生这种情况,如何修复呢?
这些是我的变量:
@NotNull
@DateTimeFormat(pattern = "dd/mm/yyyy")
private Date startDate;
@DateTimeFormat(pattern = "dd/mm/yyyy")
private Date endDate;
英文:
I have Spring Boot app with PostgreSQL. When I save a date like 2020-07-28 в 17:30:00, in PostgreSQL it looks 2020-07-28 в 06:30:00. Sometimes the difference is 12 hours sometimes 11. In front-end it comes in right way, but when I export it in cvs wrong date comes out. Why it happens and how it fix?
These are my variables:
@NotNull
@DateTimeFormat(pattern = "dd/mm/yyyy")
private Date startDate;
@DateTimeFormat(pattern = "dd/mm/yyyy")
private Date endDate;
答案1
得分: 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));
我在数据库和前端中使用这种方法,效果还不错。
英文:
The java.util.Date is pretty annoying to be honest. If you want to play with it, in database or in front you should better use LocalDateTime as said. However if you want to continue using java.util.Date, I have found a way that worked for me but is pretty much just bypassing the problem. If you want you can try using it like that :
Date startDate;
SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.Out.println(formater.format(startDate));
I used this to insert in DB and in front-end and worked pretty well for me
答案2
得分: 0
避免使用 java.util.Date
和 java.sql.Date
类。随着现代 java.time 类取而代之,连同 Calendar
和 SimpleDateFormat
,这些类现在已经是过时的。
JDBC 4.2+ 中的 java.time 类
如果您想要记录一个时刻,时间线上的特定点,请使用:
- 在 Postgres 中,使用类型为
TIMESTAMP WITH TIME ZONE
的列。注意使用WITH
而不是WITHOUT
(后者无法表示一个时刻)。 - 在 Java 中,使用
Instant
、OffsetDateTime
或ZonedDateTime
。
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 上已经有很多很多次讨论。因此我简要说明。请搜索以获取更多信息。
英文:
Avoid Date
Never use the java.util.Date
or java.sql.Date
classes. Along with Calendar
and SimpleDateFormat
, these are now legacy, supplanted years ago by the modern java.time classes.
java.time classes with JDBC 4.2+
If you are trying to record a moment, a specific point on the timeline, use:
- In Postgres, a column of type
TIMESTAMP WITH TIME ZONE
. Notice theWITH
rather thanWITHOUT
(which cannot represent a moment). - In Java,
Instant
,OffsetDateTime
, orZonedDateTime
.
JDBC 4.2 and later lets us exchange java.time objects with the database. But oddly, JDBC 4.2 requires support only for OffsetDateTime
but not the two more commonly used types. Fortunately, converting is easy.
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 ) ;
You may be able to pass that to your particular JDBC driver.
myPreparedStatement.setObject( … , zdt ) ;
If not, convert to OffsetDateTime
.
myPreparedStatement.setObject( … , zdt.toOffsetDateTime() ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Adjust to your desired time zone.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Present to the user, as text, localized.
Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( f ) ;
See the same moment in UTC. A Instant
object is always in UTC, by definition.
Instant instant = zdt.toInstant() ;
Using the code seen here will eliminate your time zone surprises.
All this has been covered many many many times already on Stack Overflow. So I was brief. Search to learn more.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论