Java MySql日期时间不存储为UTC,而是存储在服务器时区中

Java MySql日期时间不存储为UTC,而是存储在服务器时区中,java,mysql,datetime,timezone,Java,Mysql,Datetime,Timezone,Mysql数据库:将java日期存储到datetime类型的数据库列中,例如 Table Foo id time --------------------- bigint(20) datetime 日期是 01/15/19 19:00:00 (Time Zone: UTC+1:00), DateFormat df = new SimpleDateFormat('MM/dd/yy HH:mm:ss'); df.setTimeZone("Europ

Mysql数据库:将java日期存储到datetime类型的数据库列中,例如

    Table Foo
    id         time
   ---------------------
   bigint(20)   datetime
日期是

01/15/19 19:00:00 (Time Zone: UTC+1:00),

DateFormat df = new SimpleDateFormat('MM/dd/yy HH:mm:ss');
df.setTimeZone("Europe/Paris");   // UTC+1:00
Date date = df.parse("01/15/19 19:00:00");

PreparedStatement st = new PreparedStatement("insert into Foo (id, time) values (?, ?)";
st.setObject(1, 1);
st.setObject(2, date);
st.executeUpdate();  
预计将转换为

01/15/19 18:00:00 UTC
并存储在数据库中

MySql时区是系统(UTC-6:00)。JVM时区为UTC-6:00。两者都在同一台机器上运行。存储的值为01/15/19 12:00:00。为什么它被储存在 服务器时区(非UTC)

从Foo中选择时间

time
-------------------
2019-01-15 12:00:00
更改服务器时区不会影响select值

mysql> set time_zone='+8:00';

select time from Foo;

    time
    -------------------
    2019-01-15 12:00:00
tl;博士 使用现代java.time类,不要使用
java.util.Date
java.sql.Date
java.sql.Timestamp

myPreparedStatement                   // With JDBC 4.2, wa can directly exchange java.time objects with the database.
.setObject(                           // Pass a `OffsetDateTime` object representing the moment we want stored in the database.
    LocalDateTime.parse(              // Parse the input string lacking an indicator of offset or zone.
        "2019-01-19T19:00"            // When using strings in standard ISO 8601 format, no need to specify a formatting pattern.
    )                                 // Returns a `LocalDateTime`, an ambiguous value without real meaning.
    .atZone(                          // Apply a time zone to give meaning to the `LocalDateTime`. 
        ZoneId.of( "Europe/Paris" )   // Here we are saying "the 7 PM on that date as seen on the clock on the wall of someone standing in Paris France".
    )                                 // Returns a `ZonedDateTime` object.
    .toOffsetDateTime()               // Returns an `OffsetDateTime` object as demanded by the JDBC spec, stripping off the time zone to leave on the hours-minutes-seconds from UTC.
)
java.time 您正在使用可怕的日期时间类,这些类在几年前被java.time类取代。尝试调试/理解遗留类是毫无意义的,因为它们非常糟糕

LocalDateTime
将输入字符串解析为
LocalDateTime
,因为它缺少或的任何指示符

尽可能养成使用日期时间文本标准格式的习惯。对于带有时间的日期,什么是YYYY-MM-DDTHH:MM:SS,其中
T
将日期部分与时间部分分开

String input = "2019-01-19T19:00" ;
LocalDateTime ldt = LocalDateTime.parse( input ) ; // No need to specify formatting pattern when using standard ISO 8601 formats.
ZoneDateTime
LocalDateTime
类也缺少任何区域或偏移的概念。因此,此类对象并不代表一个时刻,也不是时间线上的一个点。它代表了大约26-27小时范围内的潜在时刻,即全球各个时区

你似乎肯定知道这个日期和时间是用来代表特定时区的一个时刻的。因此,应用一个时区,赋予我们模棱两可的
LocalDateTime
对象意义

大陆/地区
的格式指定,例如
美国/蒙特利尔
非洲/卡萨布兰卡
,或
太平洋/奥克兰
。切勿使用2-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

如果要使用JVM的当前默认时区,请请求它并将其作为参数传递。如果省略,代码将变得模棱两可,我们无法确定您是否打算使用默认值,或者您是否像许多程序员一样不知道这个问题

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
现在我们可以应用
ZoneId
来获得
zoneDateTime

ZonedDateTime zdt = ldt.atZone( z ) ;
OffsetDateTime
您的JDBC可能接受
ZonedDateTime
对象,但JDBC 4.2规范要求它接受
OffsetDateTime
。有什么区别?
ZonedDateTime
OffsetDateTime
都代表一个时刻,即时间线上的一个点。偏移量只是UTC前后的小时分秒数。时区更重要。时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史。所以时区总是更可取的。除此之外,我们使用JDBC与数据库交换java.time对象,我们使用
OffsetDateTime
编写标准代码

OffsetDateTime odt = zdt.toOffsetDateTime() ;  // Convert from moment with time zone to a moment with merely an offset-from-UTC.
现在我们可以把这一刻留给你准备好的声明

myPreparedStatement( … , odt ) ;  // Pass a `OffsetDateTime` moment as the value for a placeholder in the SQL of your prepared statement.
检索

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
指定所需的时区

ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
上面几行中看到的
odt
zdt
都代表了非常相同的同时时刻,即时间线上的同一点。只有它们的挂钟时间不同,因为大多数数据库存储和检索UTC,而您想查看巴黎时间


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
java.sql.*

从哪里获得java.time类

  • 、和更高版本-标准Java API的一部分,带有捆绑实现。
    • Java9添加了一些次要功能和修复
    • 大多数java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类

    • 对于早期的Android(你的客户机时区是什么?mysql客户机?选择@时区:系统。系统时区是UTC-6:00。插入的内容到底是什么样子的?数据库列的数据类型是什么?如果我的记忆正常,mysql有一个带有时区的
      时间戳
      数据类型,这将确保时间戳存储在UTC中。@DanFarrell Update预计起飞时间。
      ZoneId z = ZoneId.of( "Europe/Paris" ) ;
      ZonedDateTime zdt = odt.atZone( z ) ;