[英]How to convert UTC DateTime to another Time Zone using Java 8 library?
[英]MySql datetime is not stored as UTC, but in server time zone
Mysql数据库:将Java Date存储到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时区是SYSTEM(UTC-6:00)。 JVM时区为UTC-6:00。 两者都在同一台计算机上运行。 存储的值为01/15/19 12:00:00。 为什么将其存储在服务器时区(而不是UTC)中?
从Foo中选择时间;
time
-------------------
2019-01-15 12:00:00
更改服务器时区不会影响选择值。
mysql> set time_zone='+8:00';
select time from Foo;
time
-------------------
2019-01-15 12:00:00
使用现代的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类所取代。 尝试调试/理解遗留类确实没有任何意义,因为遗留的类很糟糕。
LocalDateTime
将您的输入字符串解析为LocalDateTime
因为它缺少任何时区或从UTC偏移的指示。
养成尽可能在日期时间文本中使用标准ISO 8601格式的习惯。 对于带有日期的日期,则为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.
ZonedDateTime
LocalDateTime
类也缺少区域或偏移量的任何概念。 因此,此类的对象不能表示时刻, 也不是时间轴上的一点。 它代表了全球各个时区大约26-27小时的潜在时刻。
您似乎肯定知道此日期和时间旨在表示特定时区中的时刻。 因此,请应用一个时区,以使我们含糊的LocalDateTime
对象有意义。
以Continent/Region
的格式指定正确的时区名称 ,例如America/Montreal
, Africa/Casablanca
或Pacific/Auckland
。 切勿使用2-4字母的缩写,例如EST
或IST
因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
如果要使用JVM的当前默认时区,请提出要求并作为参数传递。 如果省略,代码将变得难以理解,因为我们不确定您是否打算使用默认值,或者您是否像许多程序员一样不知道该问题。
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
现在我们可以应用ZoneId
来获取ZonedDateTime
。
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框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.Date
, Calendar
和SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参见Oracle教程 。 并在Stack Overflow中搜索许多示例和说明。 规格为JSR 310 。
您可以直接与数据库交换java.time对象。 使用与JDBC 4.2或更高版本兼容的JDBC驱动程序 。 不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。 该项目为将来可能在java.time中添加内容提供了一个试验场。 您可以在这里找到一些有用的类,比如Interval
, YearWeek
, YearQuarter
,和更多 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.