简体   繁体   English

从MySQL DB中选择日期后退日期一天

[英]Date one day backwards after select from MySQL DB

I have timezone related problem. 我有与时区有关的问题。

I have a program in JAVA and MySql database. 我在JAVA和MySql数据库中有一个程序。 I do not use any ORM, but I have custom jdbc library which uses mysql connector java v 6.0.4 我没有使用任何ORM,但是我有使用mysql连接器Java v 6.0.4的自定义jdbc库

I send settings as part of the connection string as: 我将设置作为连接字符串的一部分发送为:

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

I try to select a date from db eg 2019-02-13 . 我尝试从数据库中选择一个日期,例如2019-02-13

Database is located at time zone US/Eastern and server running java program is located at time zone America/Chicago. 数据库位于美国/东部时区,运行Java程序的服务器位于美国/芝加哥时区。

There is no way to change the location / time zone of any of the servers. 无法更改任何服务器的位置/时区。

In Java, I get a date one day backwards ( 2019-02-12 ). 在Java中,我将日期向后退了一天( 2019-02-12 )。 Problem is caused because of timestamp - 问题是由于时间戳引起的-

1550034000 is 2019-02-13 00:00:00 in US/Eastern 15500340002019-02-13 00:00:00在美国/东部

but

1550034000 is 2019-02-12 23:00:00 in America/Chicago 15500340002019-02-12 23:00:00在美国/芝加哥

So as the result I have java.sql.Date object with date 2019-02-12 . 因此,结果是我有日期为2019-02-12 java.sql.Date对象。 There is no help to add timezone offset because time information is cut off from date. 由于时间信息已从日期开始中断,因此添加时区偏移没有帮助。

Can you propose some solution on how to get a proper date without timezone shift? 您能否提出一些解决方案,以解决如何在不更改时区的情况下获得正确日期的问题?

Edit: I am using serverTimezone setting but I am not sure if value should be timezone that database is using or it is just overriding timezone of JVM / server running the application. 编辑:我正在使用serverTimezone设置,但我不确定值是否应该是数据库正在使用的时区,或者它只是覆盖运行应用程序的JVM /服务器的时区。

First, I have read that you can't in your case, but for other readers I would like to state that the general recommendation is to run everything in UTC, at least when you span more than one time zone. 首先,我读到您不能以您的情况为准,但是对于其他读者,我想指出,一般的建议是至少在跨越多个时区的情况下,以UTC运行所有内容。 So this would have been the best solution to your issue. 因此,这将是解决您问题的最佳解决方案。

Second, as both I and Gord Thompson have mentioned in comments, the second best solution is to handle dates as LocalDate , not java.sql.Date . 其次,正如我和Gord Thompson在评论中都提到的那样,第二好的解决方案是将日期作为LocalDate而不是java.sql.Date While the latter only pretends not to have time of day, it really has design problems that make it hard to solve your issue. 尽管后者只是假装没有时间,但实际上存在设计问题,很难解决您的问题。 A LocalDate really is a date without time of day and without time zone, so should be a bet that is a lot safer (except that database drivers that convert incorrectly to and from LocalDate have been heard of; I keep my fingers crossed; again running everything in UTC would eliminate those bugs too). LocalDate实际上一个没有时间和时区的日期,因此应该选择一个更安全的押注(除非听说过不正确地与LocalDate转换的数据库驱动程序;我不停地LocalDate手指;再次运行) UTC中的所有内容也将消除这些错误)。 Edit: Assuming you can modify your custom JDBC library, here's how to get a LocalDate from a ResultSet : 编辑:假设您可以修改自定义JDBC库,这是从ResultSet LocalDate的方法:

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

It requires at least JDBC 4.2, you probably have that. 它至少需要JDBC 4.2,您可能已经拥有了。

If none of the above is available to you, here comes the way to mend the incorrect Date you got from the database. 如果以上都不可用,则可以使用这种方法来修复从数据库获取的错误Date It's a bit of a hack, but will work. 这有点hack,但是可以用。

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);

When I ran this in America/Chicago time zone, it printed: 当我在美国/芝加哥时区运行此代码时,它显示:

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

I have tried running it in other time zones. 我尝试在其他时区运行它。 In some time zones the first line prints 2019-02-12 , in others 2019-02-13 . 在某些时区,第一行打印2019-02-12 ,在其他时区打印2019-02-13 The last line prints 2019-02-13 in all time zones I have tried. 最后一行在我尝试过的所有时区中显示2019-02-13

Now I have given you a LocalDate . 现在我给了你一个LocalDate That's good, this is what you should want to use in your further processing. 很好,这是您应该在进一步处理中使用的东西。 In case you need a java.sql.Date for another legacy API that you don't want to change just yet, convert back to a correct java.sql.Date this way: 如果您需要一个java.sql.Date用于另一个您不想更改的旧版API,请通过以下方式转换回正确的 java.sql.Date

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

Date converted back to 2019-02-13 日期转换回2019-02-13

And when I say correct, it requires that no one is tampering with the default time zone of your JVM, which is easy for any program running in the JVM to do. 当我说对了时,它要求没有人会篡改JVM的默认时区,这对于在JVM中运行的任何程序都非常容易。

Link: Oracle tutorial: Date Time explaining how to use java.time. 链接: Oracle教程:Date Time说明如何使用java.time。

I am using serverTimezone setting but I am not sure if value should be timezone that database is using or it is just overriding timezone of JVM / server running the application. 我正在使用serverTimezone设置,但是我不确定该值是否应该是数据库正在使用的时区,或者它只是覆盖运行该应用程序的JVM /服务器的时区。

serverTimezone=America/Chicago means "interpret the results from the server as if the server was using the America/Chicago time zone regardless of the default time zone that the server is configured to use". serverTimezone=America/Chicago意思是“无论服务器配置为使用默认时区,都将服务器的结果解释为好像服务器正在使用America/Chicago时区”。 So if you used that setting in your connection string you would get Timestamp values converted to America/Chicago even though the default time zone for the server is apparently America/New_York . 因此,如果您在连接字符串中使用了该设置,则即使服务器的默认时区显然是America/New_York也会将Timestamp值转换为America/Chicago

However, before committing to that approach you'd want to confirm that the server really is using America/New_York (which would presumably switch back and forth between Eastern Standard Time and Eastern Daylight Time) and not a fixed offset like UTC-5 (which would always stay on "Eastern Standard Time"). 但是,在采用该方法之前,您需要确认服务器确实在使用America/New_York (可能会在Eastern Standard Time和Eastern Daylight Time之间来回切换),而不是像UTC-5这样的固定偏移量(将始终停留在“东部标准时间”)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM