英文:
How do I get an Instant object with the timestamp 48962-08-06T23:16:59.000Z in Java
问题
我有一个日期字符串,我想将其解析为Instant:48962-08-06T23:16:59.000Z
,但是由于大多数标准的DateTimeFormatter规则不支持它,所以无法实现。
参考:https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
以下是我尝试使用自定义格式化器的操作示例:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendValue(YEAR, 5, 10, SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.appendLiteral('T')
.appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.appendFraction(NANO_OF_SECOND, 0, 9, true)
.appendLiteral('Z')
.toFormatter();
Instant value = Instant.from(formatter.parse("48962-08-06T23:16:59.000Z"));
但是它失败并显示错误消息:无法从TemporalAccessor获取Instant:{},ISO解析为类型为java.time.format.Parsed的+48962-08-06T23:16:59
。
英文:
I have a date string which I want to parse as Instant
48962-08-06T23:16:59.000Z
but unable to do as most of standard DateTimeFormatter rules are not supporting it.
Ref: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html
Here is what I was trying to do, using my custom formatter
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendValue(YEAR, 5, 10, SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.appendLiteral('T')
.appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.appendFraction(NANO_OF_SECOND, 0, 9, true)
.appendLiteral('Z')
.toFormatter();
Instant value = Instant.from(formatter.parse("48962-08-06T23:16:59.000Z"));
But it fails with Unable to obtain Instant from TemporalAccessor: {},ISO resolved to +48962-08-06T23:16:59 of type java.time.format.Parsed
答案1
得分: 4
在我的机器上,以下代码解析了您未来的年份:
public static void main(String[] args) {
String dateTime = "48962-08-06T23:16:59.000Z";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuuu-MM-dd'T'HH:mm:ss.SSSz");
Instant instant = Instant.from(dtf.parse(dateTime));
System.out.println(instant);
}
并且输出
+48962-08-06T23:16:59Z
我认为您的代码问题可能出在以下一行(或两行):
.appendFraction(NANO_OF_SECOND, 0, 9, true)
.appendLiteral('Z')
因为在String
中,点号后面且Z
前面的三个数字可能不是纳秒,而是秒的分数部分。另一行代码也可能有问题,但我不能确定问题所在。我只知道,将模式中的小写z
更改为大写Z
时,我的答案会抛出异常。
您可以调整DateTimeFormatter
中的内容,然后再次尝试,可能会起作用。
英文:
On my machine, the following code parses your future year:
public static void main(String[] args) {
String dateTime = "48962-08-06T23:16:59.000Z";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuuu-MM-dd'T'HH:mm:ss.SSSz");
Instant instant = Instant.from(dtf.parse(dateTime));
System.out.println(instant);
}
and outputs
+48962-08-06T23:16:59Z
I think the problem with your code is one (or both) of the lines
.appendFraction(NANO_OF_SECOND, 0, 9, true)
.appendLiteral('Z')
because the three digits after the dot and before the Z
in the String
might not be nanos of second but rather fraction of second.
And the other line might be problematic, too, but I can't really tell you why. I only know that my answer would throw an exception when the z
(lower case) in the pattern is changed to a Z
(upper case).
You could adjust that in your DateTimeFormatter
and try again, might work.
答案2
得分: 3
我同意你的观点,使用构建器是一个不错的解决方案。以下代码解析了包含4位和5位数年份的日期:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 5, SignStyle.NOT_NEGATIVE)
.appendPattern("-MM-dd'T'")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendOffsetId()
.toFormatter();
String dateTime = "48962-08-06T23:16:59.000Z";
Instant i = formatter.parse(dateTime, Instant::from);
System.out.println(i);
代码片段的输出结果为:
+48962-08-06T23:16:59Z
你的基本问题在于你的字符串不符合 ISO 8601 标准,而 java.time
类的默认解析方式就是按照这个标准进行解析的,即在没有明确指定格式化器的情况下。ISO 8601 允许使用超过4位数字的年份,但在这种情况下需要使用符号(正如你在输出中看到的)。在你的代码中出了什么问题?正如 Joachim Sauer 在评论中指出的,将 Z
硬编码为文字是错误的。Z
代表与 UTC 的偏移量为0,并且需要被解析为一个偏移量。由于你的格式化器没有解析任何偏移量,它无法从解析的信息中确定一个时间点,即一个时刻。这就是你收到的错误消息的含义:
Unable to obtain Instant from TemporalAccessor: {},ISO resolved to
+48962-08-06T23:16:59 of type java.time.format.Parsed
英文:
I agree with you that the nice solution is using a builder. The following one parses years with both 4 and 5 digits:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 5, SignStyle.NOT_NEGATIVE)
.appendPattern("-MM-dd'T'")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendOffsetId()
.toFormatter();
String dateTime = "48962-08-06T23:16:59.000Z";
Instant i = formatter.parse(dateTime, Instant::from);
System.out.println(i);
Output from the snippet is:
> +48962-08-06T23:16:59Z
Your basic problem is that your string doesn’t conform with ISO 8601, the standard that the classes of java.time parse as their default, that is, without any explicit formatter. Years with more than 4 digits can be allowed in ISO 8601, but then a sign is required (as you can also see in the output above).
What went wrong in your code? Joachim Sauer is correct in the comment: Hardcoding Z
as a literal is wrong. It’s an offset of 0 from UTC and needs to be parsed as an offset. Since your formatter didn’t parse any offset, it was unable to determine a point int time, an instant, from the parsed information. This was what your error message meant:
> Unable to obtain Instant from TemporalAccessor: {},ISO resolved to
> +48962-08-06T23:16:59 of type java.time.format.Parsed
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论