当前位置: 首页 > 知识库问答 >
问题:

Java和MySQL中的时间戳和时区转换

孙乐逸
2023-03-14

我正在开发一个带有MySQL数据库的Java应用程序,该数据库位于与我的服务器不同的时区,我正试图决定在我的数据库上使用DATETIME还是TIMESTAMP。

在阅读了诸如我应该使用字段'datetime'还是'TIMESTAMP'之类的问题,以及MySQL文档之后,我认为TIMESTAMP更适合我,因为它将值转换为UTC以存储,并返回到当前时区以进行检索。

此外,正如用户Jesper在本文中所解释的,java.util.Date对象在内部只是一个UTC时间戳(即,自纪元以来的毫秒数),当您执行toString()时,它将根据当前时区显示。

对我来说,那看起来是一个很好的实践:将datetimes存储为UTC时间戳,然后根据当前时区显示它们。

难道MySQL不会假设这个时间戳是UTC格式的,然后检索一个不正确的本地化值吗?

共有1个答案

钱运浩
2023-03-14

Teo的回答中的第一段相当有洞察力和正确:Java中的日期-时间处理是一团糟的。对于我所知道的所有其他语言和开发环境也是如此。日期时间工作是困难和棘手的,特别是容易出错和令人沮丧的,因为我们认为它是日期时间的直觉。但“直觉”并不是在涉及数据类型、数据库、序列化、本地化、跨时区调整以及所有其他随计算机编程而来的程序时。

不幸的是,计算机行业基本上选择了忽略这个日期-时间工作的问题。就像Unicode的发明花了太长的时间来满足明显的需求一样,业界在解决日期-时间处理问题上也是一败涂地。

但我必须不同意它的结论。使用count-sine-epoch不是最好的解决方案。使用Count-Sine-Epoch本质上是令人困惑的、容易出错的和不兼容的。

    null
String sql = "SELECT now();";
…
java.sql.Timestamp now = myResultSet.getTimestamp( 1 );
DateTime dateTimeUtc = new DateTime( now , DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );

在此之前,我认为时间戳按照惯例总是使用UTC。究竟为什么会有人想要一个本地化的时间戳而不是它的本地化表示呢?那不是大家都很困惑吗?

的确如此。SQL标准定义了一个不带时区的时间戳,它忽略并删除了包含的任何时区数据。我无法想象那有什么用处。Postgres专家David E.Wheeler同样建议始终使用timestamp WITH TIME zone。Wheeler引用了一个狭义的技术例外(分区),甚至还说在保存到数据库之前自己将所有值转换为UTC。

最佳实践是以UTC方式工作和存储数据,同时调整为本地化时区以向用户显示。可能有些时候,您希望记住其本地化时区中的原始日期-时间数据;如果是的话,除了转换为UTC之外,还要保存该值。

    null
    null

从JDBC4.2和更高版本开始,我们可以直接与数据库交换java.time对象。使用getObject&setObject方法。

myPreparedStatement.setObject( … , Instant.now() ) ;

检索。

Instant instant = myResultSet.getObject( … , Instant.class ) ;

JDBC 4.2规范要求驱动程序支持offsetdatetime,但奇怪的是,它不要求支持更常见的类型instantzoneddatetime。但是在类型之间转换是相当容易的。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
  • Java SE 8、Java SE 9、Java SE 10及更高版本
  • 内置。
  • 带有捆绑实现的标准Java API的一部分。
  • Java 9添加了一些小功能和修补程序。
  • Java SE 6和Java SE 7
  • 大部分Java.time功能在threeten-backport中后端移植到Java6&7。
  • Android
  • java.time类的Android捆绑实现的更高版本。
  • 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen-Backport(上面提到)。查看如何使用ThreeTenabp…。

ThreeTen-Extra项目使用额外的类扩展了java.time。这个项目是将来可能添加java.time的一个试验场。您可以在这里找到一些有用的类,如intervalyearweekyearquard等等。

 类似资料:
  • 然后将变量持久化到MySQL表列中。 然而,虽然通过调试,我看到对象显示在正确的时区GMT+1,但在数据库上持久化时,它是一个GMT时区,所以要追溯一个小时。 使用函数返回一个GMT+1日期。 连接字符串为,没有任何参数。 编辑:找到这段代码

  • 它给出了准备好的SQL语句字符串: 无论我指定的时区如何,返回的时间戳都是相同的时间戳。它忽略了我指定的带有时区的Calendar对象。这是怎么回事,我做错了什么?

  • 问题内容: 在Java应用程序中,使用日期时间和时间戳的混合在MySQL数据库中添加和输入日期信息方面有什么好的折衷办法? 问题答案: 在Java方面,日期通常由(设计欠佳,但不包括在内)表示。它基本上是由支持大纪元时间中的味道long,也称为时间戳。它包含有关日期和时间部分的信息。在Java中,精度以毫秒为单位。 在SQL方面,有几个标准的日期和时间类型,DATE,TIME和TIMESTAMP(

  • 问题内容: 解决的问题 外部设备正在计算并发送非标准的2小时轮班时间戳,这使我非常困惑,并启动了该线程。时区 不会影响自己的时间戳 ,时区仅在以人类可读形式进行转换时适用。 我在UTC时区有时间戳记(距离unix纪元的秒数​​),没有DST(夏令时)。 我想要使​​用DST的“欧洲/布拉格”时区中的时间戳(距Unix纪元的秒数​​)。 我曾经以为unix时间戳不受时区限制,时区仅影响将时间戳转换为

  • 问题内容: 如何将Unix时间戳中的时间转换为正常时间? 问题答案: 您的问题含糊不清。我将消除时区的歧义。 如何将Unix时间戳中的时间转换为正常时间? 我怀疑您是以某种方式从数据库而不是从中获取或一个值。在JDBC中,通常希望使用适当的方法来获取特定于DB的数据类型。可以获取MySQL 数据类型,从而为您提供,而后者又是的子类。 简而言之,应该执行以下操作: 要将其呈现给最终用户时,要以人类可

  • 我不太理解时间戳的用法, 例如 用户创建文章,他们可以选择,系统也会自动存储。 a.我是否应该使和具有时区并设置UTC的时间戳? b.用户post字符串,然后将其转换为utc时间戳,如下所示使用并存储,当某人选择这一行时,将其显示为用户客户端时间反向使用 c.我使用到,是不是意味着服务器时间?我做得对吗? 我的想法是,我总是在数据库中插入utc时区时间戳,无论用户/客户端读取的地方,都将数据转换为