Java 根据用户时区转换存储在中心时间的服务器日期时间戳
带有时间戳的日期插入/保存到数据库中,数据类型为中心时间(CT)中的datetime,与时区无关。当我访问东部时区中的应用程序并从我的时区(东部时间(ET))检索这些日期时,我希望这些日期以东部时区而不是中部时间呈现。例如,如果在中央时间数据库中存储的日期是2018-11-19 13:08:44,则如果我从东部连接,则需要将其返回为2018-11-19 14:08:44;如果我从山区时区连接,则需要将其返回为2018-11-19 12:08:44。我有一个JavaBean,我需要将检索到的日期转换为我的时区,并在csv文件中显示该日期。我如何做到这一点?Java是服务器端语言。非常感谢。您没有提供足够的详细信息来为您提供准确的帮助。但这里有一些一般的指导方针 列的数据类型 要记录时刻,您的数据库表列必须使用类似于SQL标准带时区的时间戳的类型定义。MySQL中的等价物似乎是 当心那些具有反时限功能的工具,这些工具动态地将默认时区应用于从数据库中提取的值。这造成了存储值具有特定时区的错觉。MySQL 8中肯定不是这种情况,Java 根据用户时区转换存储在中心时间的服务器日期时间戳,java,mysql,datetime,plsql,java-8,Java,Mysql,Datetime,Plsql,Java 8,带有时间戳的日期插入/保存到数据库中,数据类型为中心时间(CT)中的datetime,与时区无关。当我访问东部时区中的应用程序并从我的时区(东部时间(ET))检索这些日期时,我希望这些日期以东部时区而不是中部时间呈现。例如,如果在中央时间数据库中存储的日期是2018-11-19 13:08:44,则如果我从东部连接,则需要将其返回为2018-11-19 14:08:44;如果我从山区时区连接,则需要将其返回为2018-11-19 12:08:44。我有一个JavaBean,我需要将检索到的日期转
TIMESTAMP
始终存储在UTC中
不要使用不带时区的时间戳类型,因为它只记录一天中的日期和时间,而不记录时区上下文或UTC偏移量。MySQL中的等价物似乎是
UTC是你的朋友
通常,最好通过UTC跟踪时刻,也就是说,与UTC的偏移量为零小时分秒。您应该学会将UTC视为一个真实时间,所有其他区域和偏移都只是变化。所有程序员和系统管理员都应该在UTC中进行日志记录、调试、数据存储和数据交换。仅根据业务逻辑或向用户演示的需要应用时区
插入/保存到数据库中,数据类型为中心时间(CT)中的datetime,与时区无关
我不知道那是什么意思
如果要跟踪时间轴上的时刻、特定点,必须具有时区或与UTC的偏移量。正如我所建议的,强烈建议使用UTC本身
在java.time中,Instant
类表示UTC中的一个时刻,总是UTC
Instant instant = Instant.now() ; // Capture current moment in UTC.
奇怪的是,JDBC 4.2标准不需要支持两个最常用的java.time类:Instant
和ZonedDateTime
。第三类是“时刻”OffsetDateTime
。没关系,我们可以很容易地转换。使用常量指定零的偏移量
或者跳过即时
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
发送到数据库
myPreparedStatement.setObject( … , odt ) ;
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
从数据库中检索
myPreparedStatement.setObject( … , odt ) ;
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
请注意,所有这些代码仅在UTC中工作。没有涉及时区,只是零小时分秒的偏移量
时区
中部时间(CT)…东部时间(ET)
这些不是时区。这些是伪区域,通常在媒体中使用,但永远不会在编程中使用
以大陆/地区
的格式指定,例如美国/蒙特利尔
,非洲/卡萨布兰卡
,或太平洋/奥克兰
。切勿使用2-4个字母的缩写,如EST
或IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)
ZoneId
虽然ZoneOffset
仅用于偏移量(小时分秒数),但该类用于时区(特定地区的人们使用的偏移量的过去、现在和未来变化的历史记录)
ZoneDateTime
我们可以将ZoneId
应用于Instant
或OffsetDateTime
以通过该地区的人们使用的挂钟时间(offset)查看该时刻
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
正文
要以标准ISO 8601格式创建表示java.time对象值的字符串,只需调用toString
要以其他自定义格式生成文本,甚至自动本地化,请参见DateTimeFormatter
和DateTimeFormatterBuilder
类。搜索堆栈溢出,因为这已经被讨论过很多次了
重构
你在问题中提到了“日期时间”。如果你的意思是你的专栏实际上是DATETIME
类型,那么你的手上就乱七八糟了。您应该重构数据库以使用适当的类型
对于重构,从该列中提取值,作为Java类型进行检索。此类用于日期和时间,但缺少区域或偏移的上下文。因此,该值不是一个时刻,也不是时间线上的一个点
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ; // Retrieving value from a MySQL 8 column of type `DATETIME`.
您声称知道这些值的预期时区,但未记录。记住,你只是在猜测。您无法确定原始分区/偏移是什么,因为该值已被丢弃
但是,如果您确定要使用的分区,请指定为ZoneId
。所谓“中央时间(CT)”,我假设你指的是一个时区,比如美国/芝加哥
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
将此ZoneId
对象应用于每个检索到的LocalDateTime
对象
ZonedDateTime zdt = ldt.atZone( zChicago ) ;
根据JDBC 4.2规范所需的支持,将我们的ZonedDateTime
转换为OffsetDateTime
。(您的JDBC驱动程序可以选择支持ZonedDateTime
,因此,如果您愿意,可以尝试这样做。)
在类型为TIMESTAMP
的新列中发送到数据库,就像最初设计数据库时应该做的那样
myPreparedStatement.setObject( … , odt ) ;
请注意,我们发送的OffsetDateTime
对象不是UTC格式。该对象将携带芝加哥地区在该位置使用的偏移量
myPreparedStatement.setObject( … , odt ) ;