为什么SimpleDateFormat总是忽略连接的时区?

我在 Java 中遇到 Date 和 SimpleDateFormat 对象的一些问题。我知道我需要在 Java 8 中使用新的日期和时间 API 来切换它们,我想这样做,但我有一个问题。当我从数据库中检索我的日期时(它是 SimpleDateFormat 并且我无法更改它),并且当我想添加一些小时(例如下午 4 点),然后我需要在用户从下拉列表中选择的时区中(假设美国/加拉加斯),所以我希望美国/加拉加斯的结果是 16 小时,但在我的情况下是 16 小时 UTC + UTC 和美国/加拉加斯之间的差异。这是我的代码:

Date startDate -> it's value is Tue Feb 23 20:00:00 CET 2021
Date date = new SimpleDateFormat("yyy-MM-dd").format( startDate + 4:00PM + America/Caracas);

但是,奇怪的是,这种格式化广告 4 PM 值但不知何故忽略了时区的那部分。所以,相反,我在美国/加拉加斯有 20 小时,我在 UTC 时间有 20 小时。有人可以帮助我吗?

回答

时间

你说:

需要使用 Java 8 中的新日期和时间 API 切换它们

是的,一点没错。遗留DateCalendarSimpleDateFormat类很糟糕:令人困惑和有缺陷。

你说:

当我从数据库中检索我的日期时(它是 SimpleDateFormat 并且我无法更改它)

如果您的日期时间值正确存储在数据库中的日期时间列中,则它没有“格式”,因为它不是文本。

存储在日期时间列中的日期时间值应作为日期时间对象而不是文本进行检索。如果您正在接收文本,您应该回溯数据的食物链以解决该问题。

分区

如果存储在类型类似于 SQL-standard 的列中TIMESTAMP WITH TIME ZONE,则检索为OffsetDateTime.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

你说:

我想增加一些时间(例如下午 4 点)

这是一个矛盾。你想增加四个小时吗?

OffsetDateTime odtFourHoursLater = odt.plusHours( 4 ) ;

或者您想将时间设置为下午 4 点?

OffsetDateTime odtSetToFourPm = odt.with( LocalTime.of ( 16 , 0 ) ) ;

你说:

结果我需要在用户从下拉列表中选择的时区(假设美国/加拉加斯),

OffsetDateTimeJDBC 4.2 支持的类表示通过与 UTC 的偏移量(小时-分钟-秒)看到的时刻。大多数数据库会以零时分秒的偏移量将这个对象交付给您。

了解时区不是偏移量。时区是特定地区人民使用的偏移量的过去、现在和未来变化的命名历史。时区的名称格式为Continent/Region.

要表示在时区中看到的时刻而不是偏移量,请使用ZonedDateTime类。

ZoneId zoneId = ZoneId.of( "America/Caracas" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId ) ;

我无法提供更具体的代码示例,因为您的问题令人困惑。您的确切目标尚不清楚。

未划

如果存储在类型类似于 SQL-standard 的列中TIMESTAMP WITHOUT TIME ZONE,则检索为LocalDateTime.

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

这种类型不能代表一个时刻,时间轴上的一个点。缺乏时区的上下文或与 UTC 的偏移意味着我们不知道,例如,特定日期的中午是日本东京的中午、法国图卢兹的中午还是美国俄亥俄州托莱多的中午——所有不同的时刻,相隔几个小时。因此,此类型无法调整为任意时区。


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 & JPA 2.2 支持java.timejava.sql.*

从哪里获得 java.time 类?

  • Java SE 8 Java SE 9 Java SE 10 Java SE 11和更高版本 - 标准 Java API 的一部分,具有捆绑实现。
    • Java 9带来了一些小功能和修复。
  • Java SE 6Java SE 7
    • 大部分java.time功能在ThreeTen- Backport中向后移植到 Java 6 & 7 。
  • 安卓
    • 更高版本的 Android (26+) 捆绑了java.time类的实现。
    • 对于早期的 Android (<26),API 脱糖过程带来了java.time功能的一个子集,这些功能最初不是内置于 Android 中的。
      • 如果脱糖不能满足您的需求,ThreeTenABP项目会将 ThreeTen-Backport(如上所述)适配到 Android。请参阅如何使用ThreeTenABP ...

以上是为什么SimpleDateFormat总是忽略连接的时区?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>