从 MySQL 数据库选择后一天的日期



我有时区相关的问题。

我在JAVA和MySql数据库中有一个程序。 我不使用任何ORM,但我有自定义的jdbc库,它使用mysql连接器java v 6.0.4

我将设置作为连接字符串的一部分发送为:

serverTimezone - America/Chicago
useTimezone - true
useJDBCCompliantTimezoneShift - false
useLegacyDatetimeCode - false

我尝试从数据库中选择一个日期,例如2019-02-13.

数据库位于美国/东部时区,运行 java 程序的服务器位于时区美国/芝加哥。

无法更改任何服务器的位置/时区。

在Java中,我得到一个倒退一天的日期(2019-02-12)。 问题是由时间戳引起的 -

1550034000在美国/东部2019-02-13 00:00:00

1550034000在美国/芝加哥2019-02-12 23:00:00

因此,结果我java.sql.Date日期2019-02-12的对象。 添加时区偏移量没有帮助,因为时间信息与日期隔绝。

您能否就如何在没有时区偏移的情况下获得正确的日期提出一些解决方案?

编辑:我正在使用serverTimezone设置,但我不确定值是否应该是数据库正在使用的时区,或者它只是覆盖运行应用程序的JVM/服务器的时区。

首先,我已经读到你不能在你的情况下,但对于其他读者,我想声明一般建议是用UTC运行所有内容,至少当你跨越多个时区时。因此,这将是解决您问题的最佳解决方案。

其次,正如我和Gord Thompson在评论中提到的,第二好的解决方案是将日期处理为LocalDate,而不是java.sql.Date。虽然后者只是假装没有时间,但它确实存在设计问题,很难解决您的问题。LocalDate实际上是一个没有一天中时间和时区的日期,所以应该是一个更安全的赌注(除了听说过错误地与LocalDate之间转换的数据库驱动程序;我保持手指交叉;再次以 UTC 运行所有内容也会消除这些错误)。编辑:假设您可以修改自定义 JDBC 库,以下是从ResultSet获取LocalDate的方法:

LocalDate correctDateDirectlyFromDatabase
= yourResultSet.getObject("yourDateColumn", LocalDate.class);

它至少需要 JDBC 4.2,您可能拥有它。

如果以上都不可用,则可以通过以下方式修复从数据库中获得的错误Date。这有点黑客,但会起作用。

import java.sql.Date;
// …
// Modern ID of the time zone previously known as US/Eastern
ZoneId datebaseTimeZone = ZoneId.of("America/New_York");
Date dateFromDatabase = new Date(TimeUnit.SECONDS.toMillis(1_550_034_000));
System.out.println("Date as retrieved from database (or pretending): " + dateFromDatabase);
long epochMillis = dateFromDatabase.getTime();
ZonedDateTime dateTime = Instant.ofEpochMilli(epochMillis)
.atZone(datebaseTimeZone);
LocalDate realDate = dateTime.toLocalDate();
// Sanity check
if (! realDate.atStartOfDay(datebaseTimeZone).equals(dateTime)) {
throw new IllegalStateException("Failed to convert date correctly from " + datebaseTimeZone + " time zone");
}
System.out.println("Date is " + realDate);

当我在美国/芝加哥时区运行这个时,它打印了:

Date as retrieved from database (or pretending): 2019-02-12
Date is 2019-02-13

我尝试在其他时区运行它。在某些时区,第一行打印2019-02-12,在其他时区2019-02-13。最后一行打印2019-02-13我尝试过的所有时区。

现在我给你一个LocalDate.这很好,这是您应该在进一步处理中使用的内容。如果您需要为另一个还不想更改的旧 APIjava.sql.Date,请按以下方式转换回正确的java.sql.Date

Date oldfashionedJavaSqlDate = Date.valueOf(realDate);
System.out.println("Date converted back to " + oldfashionedJavaSqlDate);

转换回 2019-02-13 的日期

当我说正确时,它要求没有人篡改JVM的默认时区,这对于在JVM中运行的任何程序来说都很容易做到。

链接:Oracle教程:日期时间解释如何使用java.time。

我正在使用serverTimezone设置,但我不确定值是否应该是数据库正在使用的时区,或者它只是覆盖运行应用程序的JVM/服务器的时区。

serverTimezone=America/Chicago的意思是"解释来自服务器的结果,就好像服务器正在使用America/Chicago时区一样,而不管服务器配置为使用的默认时区如何"。因此,如果在连接字符串中使用该设置,即使服务器的默认时区显然是America/New_York,也会Timestamp值转换为America/Chicago

但是,在采用该方法之前,您需要确认服务器确实正在使用America/New_York(可能会在东部标准时间和东部夏令时间之间来回切换),而不是像 UTC-5 这样的固定偏移量(始终保持在"东部标准时间")。

相关内容

  • 没有找到相关文章

最新更新