为了账号安全,请及时绑定邮箱和手机立即绑定

从 MySQL DB 中选择后的日期向后一天

从 MySQL DB 中选择后的日期向后一天

森林海 2022-06-15 17:50:40
我有时区相关的问题。我在 JAVA 和 MySql 数据库中有一个程序。我不使用任何 ORM,但我有使用 mysql 连接器 java v 6.0.4 的自定义 jdbc 库我将设置作为连接字符串的一部分发送为: 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.Datedate 对象2019-02-12。添加时区偏移没有任何帮助,因为时间信息与日期截断。您能否就如何在没有时区偏移的情况下获得正确的日期提出一些解决方案?编辑:我正在使用serverTimezone设置,但我不确定值是否应该是数据库正在使用的时区,或者它只是覆盖运行应用程序的 JVM/服务器的时区。
查看完整描述

2 回答

?
ibeautiful

TA贡献1993条经验 获得超6个赞

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


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


    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. 很好,这是您在进一步处理中应该使用的。如果您需要java.sql.Date另一个您不想更改的旧 API,请通过以下方式转换回正确 java.sql.Date的 API :


    Date oldfashionedJavaSqlDate = Date.valueOf(realDate);

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

日期转换回 2019-02-13


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


查看完整回答
反对 回复 2022-06-15
?
一只斗牛犬

TA贡献1784条经验 获得超2个赞

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

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

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


查看完整回答
反对 回复 2022-06-15
  • 2 回答
  • 0 关注
  • 145 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号