将时间转换为 UTC 时间则相反

Converting time to UTC time goes the opposite way

我正在尝试使用 Java 8 DateTimeFormatter 解析偏移时间。

我住在 UTC-5 的 EST 时间,所以当我尝试转换时

2019-01-22T13:09:54.620-05:00 应该是 --> 2019-01-22T18:09:54.620

但是,使用我的代码,它获取当前时间并返回 5 小时,结果为 2019-01-22 08:09:54.620

代码:


import java.sql.Timestamp
import java.time._
import java.time.format.DateTimeFormatter

import scala.util.{Failure, Success, Try}

class MyTimeFormatter(parser: DateTimeFormatter) {

   def parse(input: String): Try[Timestamp] = {
    Try(new Timestamp(Instant.from(parser.withZone(ZoneOffset.UTC).parse(input)).toEpochMilli))
  }
}

测试:

new MyTimeFormatter(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx")).parse("2019-01-22T13:09:54.620-05:00") shouldEqual Timestamp.valueOf("2019-01-22T18:09:54.620")

其中解析器是 DateTimeFormatter 类型,输入字符串只是 "2019-01-22T13:09:54.620-05:00"

我想使用这个 parser.parse 方法而不是像 OffsetDateTime.parse(input, parser) 这样的特定时间访问器,所以我可以处理像 LocalTime, LocalDateTime, ZonedDateTime, OffsetDateTime, etc..

这样的所有情况

看起来代码只是抓取时间,减去偏移量,并将其标记为 UTC,而不是计算相对于 UTC 的偏移量。

此外,有没有办法仅在输入格式为 ZonedDateTime/OffsetDateTime 格式时应用此 UTC 转换?如果我输入 LocalDateTime(没有偏移量),例如 2017-01-01 12:45:00,解析器仍将应用 UTC 偏移量转换,因为我告诉解析器使用区域 UTC 进行解析。

虽然我无法准确重现您的问题(即使将我的时钟更改为 EST),但这是我观察到的:

Instant instant = Instant.from(parser.withZone(ZoneOffset.UTC).parse("2019-01-22T13:09:54.620-05:00"));

这会产生您预期的时间 ​​(2019-01-22T18:09:54.620Z)。

Timestamp ts = new Timestamp(instant.toEpochMilli());

因为这是基于 java.util.Date,它显示为您的当地时间。

Instant 转换为 Timestamp 的更好方法是通过 LocalDateTime,如下所示:

Timestamp ts = Timestamp.valueOf(instant.atZone(ZoneOffset.UTC).toLocalDateTime());

tl;博士

使用现代 java.time classes。仅在需要使用旧代码时才转换为遗留 class。

具体来说,将您的输入字符串解析为 OffsetDateTime 对象,通过提取 Instant 调整为 UTC,最后,转换为 java.sql.Timestamp(仅当您必须这样做时)。

java.sql.Timestamp ts =                           // Avoid using this badly-designed legacy class if at all possible.
    Timestamp                                     // You can convert back-and-forth between legacy and modern classes.
    .from(                                        // New method added to legacy class to convert from modern class.
        OffsetDateTime                            // Represents a moment with an offset-of-UTC, a number of some hours-minutes-seconds ahead or behind UTC.
       .parse( "2019-01-22T13:09:54.620-05:00" )  // Text in standard ISO 8601 format can be parsed by default, without a formatting pattern.
       .toInstant()                               // Adjust from an offset to UTC (an offset of zero) by extracting an `Instant`. 
    )                                             // Returns a `Timestamp` object. Same moment as both the `OffsetDateTime` and `Instant` objects.
;

看到这个 code run live at IdeOne.com,导致:

ts.toString(): 2019-01-22 18:09:54.62

如果使用 JDBC 4.2 或更高版本,请完全跳过 Timestamp

myPreparedStatement.setObject( … , myOffsetDateTime ) ;

祖鲁语

2019-01-22T13:09:54.620-05:00 should be --> 2019-01-22T18:09:54.620

如果您的意思是第二个值表示 UTC 中的时刻,请附加与 UTC 的偏移量以表明这一事实。 +00:00Z(发音为“Zulu”):2019-01-22T18:09:54.620Z

报告没有 UTC 偏移量或时区指示符的时刻就像报告没有货币指示符的金额。

OffsetDateTime

具有 UTC 偏移量的字符串应被解析为 OffsetDateTime 对象。

您输入的字符串恰好符合文本日期时间值的 ISO 8601 标准格式。当 parsing/generating 字符串时,java.time classes 默认使用 ISO 8601 格式。因此无需指定格式模式。

OffsetDateTime odt = OffsetDateTime.parse( "2019-01-22T13:09:54.620-05:00" ) ;

Timestamp

显然您想要一个 java.sql.Timestamp 对象。这是与 Java 的最早版本捆绑在一起的糟糕日期时间 classes 之一。这些 classes 现在是遗留的,完全被现代 java.time classes 所取代,并采用了 JSR 310。避免这些遗留 class尽可能。

如果您必须有一个 Timestamp 才能与尚未更新的旧代码互操作以使用 java.time,您可以转换。要转换,请调用添加到 old classes.

的新方法

Instant

java.sql.Timestamp class carries a from( Instant ) 方法。 Instant 是 UTC 中的一个时刻。要将我们的 OffsetDateTime 的偏移量调整为 UTC,只需提取一个 Instant.

Instant instant = odt.toInstant() ;
java.sql.Timestamp ts = Timestamp.from( instant ) ;

我们有三个对象(odtinstantts),它们都代表同一时刻。第一个有不同的挂钟时间。但是这三个都是时间轴上的同一个点。

JDBC 4.2

从JDBC 4.2开始,我们可以直接与数据库交换java.time对象。所以不需要使用Timestamp

myPreparedStatement.setObject( … , odt ) ;

……和……

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

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

您可以直接与您的数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

在哪里获取java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.