将时间转换为UTC时间的方法相反

时间:2019-01-22 18:19:47

标签: java scala datetime-format

我正在尝试使用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)这样的特定TemporalAccessor使用这种方法,因此我可以处理LocalTime, LocalDateTime, ZonedDateTime, OffsetDateTime, etc..这样的所有情况

似乎代码只是抓住时间,减去偏移量,然后将其标记为UTC,而不是计算相对于UTC的偏移量。

此外,仅当输入格式为ZonedDateTime / OffsetDateTime格式时,才可以应用此UTC转换吗?如果我输入了2017-01-01 12:45:00之类的LocalDateTime(没有偏移量),则解析器仍将应用UTC偏移量转换,因为我告诉解析器使用UTC区域进行解析。

2 个答案:

答案 0 :(得分:0)

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

pipeline = [ 
  { '$group' : {
      '_id': { '$dateToString': { 'format': "%Y-%m-%d", 'date': "$time" } },
      'macs':{ '$addToSet': '$mac' }
   } },
   {$addFields:{ 'macs':{'$size':'$macs'}}}
]

这正在产生您期望的时间(2019-01-22T18:09:54.620Z)。

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

因为这是基于Timestamp ts = new Timestamp(instant.toEpochMilli()); 的,它显示为您的本地时间。

java.util.Date转换为Instant的更好方法是通过Timestamp,就像这样:

LocalDateTime

答案 1 :(得分:0)

tl; dr

使用现代的 java.time 类。仅在需要使用旧代码时才转换为旧类。

具体来说,将输入字符串解析为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应该-> 2019-01-22T18:09:54.620

如果您要使用第二个值表示UTC时刻,请附加自UTC的偏移量以表明这一事实。 +00:00Z(读作“ Zulu”):2019-01-22T18:09:54.620Z

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

OffsetDateTime

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

您的输入字符串恰好符合ISO 8601标准格式的文本日期时间值。解析/生成字符串时, java.time 类默认使用ISO 8601格式。因此,无需指定格式设置模式。

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

Timestamp

显然您要一个java.sql.Timestamp对象。这是与最早的Java版本捆绑在一起的可怕的日期时间类之一。这些类现在已成为遗留类,并随着JSR 310的采用完全被现代的 java.time 类所取代。请尽可能避免使用这些遗留类。

如果您必须具有Timestamp才能与尚未更新以与 java.time 一起使用的旧代码进行互操作,则可以进行转换。要进行转换,请调用添加到 old 类中的新方法。

Instant

java.sql.Timestamp类带有from( Instant )方法。 Instant是世界标准时间。要将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框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

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

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore