问题
也许我在这里误用了 API 或遗漏了一些信息。这是 API 的错误还是设计缺陷?
跟进
最近我正在使用java.time
(在 scala 的 REPL 中,但它并不真正感兴趣)parse
和format
一个日期,它也包含一个偏移量但没有这样的时间:"2018-03-24+01:00"
scala> :paste
// Entering paste mode (ctrl-D to finish)
import java.time._
import java.time.temporal._
import java.time.format._
import java.util._
val f = DateTimeFormatter.ISO_OFFSET_DATE
.withLocale(Locale.GERMAN)
.withZone(ZoneId.of("GMT"))
val t = f.parse("2018-03-24+01:00")
// Exiting paste mode, now interpreting.
import java.time._
import java.time.temporal._
import java.time.format._
import java.util._
f: java.time.format.DateTimeFormatter = ParseCaseSensitive(false)(Value(Year,4,10,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2))Offset(+HH:MM:ss,'Z')
t: java.time.temporal.TemporalAccessor = {OffsetSeconds=3600},ISO,GMT resolved to 2018-03-24
到目前为止一切顺利,当尝试创建Instant.from(t)
this 时会导致异常:
scala> Instant.from(t)
java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {OffsetSeconds=3600},ISO,GMT resolved to 2018-03-24 of type java.time.format.Parsed
at java.time.Instant.from(Instant.java:378)
... 28 elided
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: InstantSeconds
at java.time.format.Parsed.getLong(Parsed.java:203)
at java.time.Instant.from(Instant.java:373)
... 28 more
ChronoFields
由于缺少所需的内容,因此这是可以预期的或至少对我来说是合理的。对此特定场景的修复可能是提供一个健全的默认时间,例如在调用后手动LocalDate.MIDNIGHT
构建一个:Instant
parse
f
scala> :paste
// Entering paste mode (ctrl-D to finish)
val i = OffsetDateTime.of(
LocalDate.from(t),
LocalTime.MIDNIGHT,
ZoneOffset.from(t)
).toInstant
// Exiting paste mode, now interpreting.
i: java.time.Instant = 2018-03-23T23:00:00Z
好吧,这解决了我当前的问题,但感觉不满意。然后我想知道在使用保存时间的格式化程序时,API 是否能够进行往返。因此,我想出了可用java.time.format.DateTimeFormatter
实例的列表,并将它们放在一个小测试函数上来验证这一点:
val dfts = scala.collection.immutable.Map(
"BASIC_ISO_DATE" -> DateTimeFormatter.BASIC_ISO_DATE,
"ISO_INSTANT" -> DateTimeFormatter.ISO_INSTANT,
"ISO_LOCAL_TIME" -> DateTimeFormatter.ISO_LOCAL_TIME,
"ISO_OFFSET_TIME" -> DateTimeFormatter.ISO_OFFSET_TIME,
"ISO_WEEK_DATE" -> DateTimeFormatter.ISO_WEEK_DATE,
"ISO_DATE" -> DateTimeFormatter.ISO_DATE,
"ISO_LOCAL_DATE" -> DateTimeFormatter.ISO_LOCAL_DATE,
"ISO_OFFSET_DATE" -> DateTimeFormatter.ISO_OFFSET_DATE,
"ISO_ORDINAL_DATE" -> DateTimeFormatter.ISO_ORDINAL_DATE,
"ISO_ZONED_DATE_TIME" -> DateTimeFormatter.ISO_ZONED_DATE_TIME,
"ISO_DATE_TIME" -> DateTimeFormatter.ISO_DATE_TIME,
"ISO_LOCAL_DATE_TIME" -> DateTimeFormatter.ISO_LOCAL_DATE_TIME,
"ISO_OFFSET_DATE_TIME" -> DateTimeFormatter.ISO_OFFSET_DATE_TIME,
"ISO_TIME" -> DateTimeFormatter.ISO_TIME,
"RFC_1123_DATE_TIME" -> DateTimeFormatter.RFC_1123_DATE_TIME
)
def test(f: DateTimeFormatter) = scala.util.Try {
Instant.from(f.parse(f.format(Instant.now)))
}
dfts.mapValues(test)
.mapValues(_.toString)
.mapValues(_.replace("java.time.temporal.UnsupportedTemporalTypeException", "j.t.t.UTTE"))
.map{ case (k,v) => f"$k%20s : $v" }
.foreach(println)
这会产生以下输出:
ISO_DATE : Failure(j.t.t.UTTE: Unsupported field: Year)
ISO_ZONED_DATE_TIME : Failure(j.t.t.UTTE: Unsupported field: Year)
BASIC_ISO_DATE : Failure(j.t.t.UTTE: Unsupported field: Year)
ISO_LOCAL_TIME : Failure(j.t.t.UTTE: Unsupported field: HourOfDay)
ISO_ORDINAL_DATE : Failure(j.t.t.UTTE: Unsupported field: Year)
ISO_LOCAL_DATE : Failure(j.t.t.UTTE: Unsupported field: Year)
ISO_DATE_TIME : Failure(j.t.t.UTTE: Unsupported field: Year)
ISO_INSTANT : Success(2018-03-25T07:48:48.360Z)
ISO_LOCAL_DATE_TIME : Failure(j.t.t.UTTE: Unsupported field: Year)
ISO_OFFSET_TIME : Failure(j.t.t.UTTE: Unsupported field: HourOfDay)
ISO_OFFSET_DATE_TIME : Failure(j.t.t.UTTE: Unsupported field: Year)
RFC_1123_DATE_TIME : Failure(j.t.t.UTTE: Unsupported field: DayOfMonth)
ISO_OFFSET_DATE : Failure(j.t.t.UTTE: Unsupported field: Year)
ISO_TIME : Failure(j.t.t.UTTE: Unsupported field: HourOfDay)
ISO_WEEK_DATE : Failure(j.t.t.UTTE: Unsupported field: WeekBasedYear)
因此,目前只有ISO_INSTANT
格式化程序正在工作,至少我希望它能够工作,因此能够在往返场景中工作。