1

I want to parse the following String into an OffsetDateTime:

OffsetDateTime test = OffsetDateTime.parse("2021-12-31T23:00:00.000+00:00");

However, this results in an exception:

java.time.format.DateTimeParseException: Text '2021-12-31T23:00:00.000+00:00' could not be parsed: null
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017) ~[na:na]
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952) ~[na:na]
    at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:402) ~[na:na]

I have seen answers online where this worked right away and I have tried creating custom formatters, but these return the same error message:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ");
OffsetDateTime test = OffsetDateTime.parse("2021-12-31T23:00:00.000+00:00", formatter);

I am using Java 11.0.17 on Windows.

Update: It works on colleagues machine, but not mine. It also does not work when I select a different Java version in IntelliJ.

Here is the complete Stacktrace (I added it somewhere randomly in the existing project as the quickest way to test it). The stack trace is from Java 19 where a bit more information is given.

java.time.format.DateTimeParseException: Text '2021-12-31T23:00:00.000+00:00' could not be parsed: Cannot invoke "java.time.temporal.TemporalAccessor.isSupported(java.time.temporal.TemporalField)" because "target" is null
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2077) ~[na:na]
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:2012) ~[na:na]
    at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:404) ~[na:na]
    at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:389) ~[na:na]
    at com.syngenio.fints.FintsServer.process(FintsServer.java:22) ~[main/:na]
    at com.syngenio.fis.controller.FintsController.fints(FintsController.java:24) ~[main/:na]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:696) ~[tomcat-embed-core-9.0.68.jar:4.0.FR]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.23.jar:5.3.23]
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) ~[spring-test-5.3.23.jar:5.3.23]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:779) ~[tomcat-embed-core-9.0.68.jar:4.0.FR]
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) ~[spring-test-5.3.23.jar:5.3.23]
    at com.syngenio.fis.integration.tests.ExemptionDateTest.testExemptionDate(ExemptionDateTest.java:53) ~[test/:na]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) ~[junit-4.13.2.jar:4.13.2]
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) ~[spring-test-5.3.23.jar:5.3.23]
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) ~[junit-4.13.2.jar:4.13.2]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) ~[spring-test-5.3.23.jar:5.3.23]
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) ~[junit-4.13.2.jar:4.13.2]
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) ~[spring-test-5.3.23.jar:5.3.23]
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) ~[spring-test-5.3.23.jar:5.3.23]
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) ~[junit-4.13.2.jar:4.13.2]
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413) ~[junit-4.13.2.jar:4.13.2]
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190) ~[spring-test-5.3.23.jar:5.3.23]
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137) ~[junit-4.13.2.jar:4.13.2]
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) ~[junit-rt.jar:na]
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) ~[junit-rt.jar:na]
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) ~[idea_rt.jar:na]
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) ~[junit-rt.jar:na]
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) ~[junit-rt.jar:na]
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) ~[junit-rt.jar:na]
Caused by: java.lang.NullPointerException: Cannot invoke "java.time.temporal.TemporalAccessor.isSupported(java.time.temporal.TemporalField)" because "target" is null
    at java.base/java.time.format.Parsed.crossCheck(Parsed.java:707) ~[na:na]
    at java.base/java.time.format.Parsed.crossCheck(Parsed.java:698) ~[na:na]
    at java.base/java.time.format.Parsed.resolve(Parsed.java:267) ~[na:na]
    at java.base/java.time.format.DateTimeParseContext.toResolved(DateTimeParseContext.java:331) ~[na:na]
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2112) ~[na:na]
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:2008) ~[na:na]
    ... 64 common frames omitted
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    I cannot reproduce this (Java (Temurin) 11.0.17 Windows 11). – Mark Rotteveel Nov 25 '22 at 12:02
  • 2
    @Fenio The error reports `Text '2021-12-31T23:00:00.000+00:00' could not be parsed`, which means the input was not null. I'd sooner guess there might be some non-printable character in there or something (though if I try that, I get a different error). – Mark Rotteveel Nov 25 '22 at 12:04
  • Does this answer your question? [OffsetDateTime parsing](https://stackoverflow.com/questions/38048032/offsetdatetime-parsing) – f1sh Nov 25 '22 at 12:05
  • 2
    @f1sh How would that answer the question? The code as given in this question is correct and works fine on my machine. – Mark Rotteveel Nov 25 '22 at 12:06
  • 1
    Related: [DateTimeParseException: fails on one host, works on another, same JDK](https://stackoverflow.com/questions/56976974/datetimeparseexception-fails-on-one-host-works-on-another-same-jdk) (no resolution though), I wonder if it is somehow related to https://bugs.openjdk.java.net/browse/JDK-8226704, but that bug is a lot older than Java 11.0.17 and is marked as resolved. However, this might suggest that the problem might be related to Locale settings on your machine. – Mark Rotteveel Nov 25 '22 at 12:15
  • 1
    What is the output of `System.out.println(java.util.Locale.getDefault())` on your machine? What is the configured region in your windows region settings, (e.g. the "Regional format") – Mark Rotteveel Nov 25 '22 at 12:20
  • That’s weird alright. I’d get hold of the source code of the JDK and debug through it. Unfortunately the line numbers of your Java 19 stack trace do not match the Java 18 source code I have at hand. – Ole V.V. Nov 27 '22 at 10:39
  • Likely diagnosis from looking through the JDK source on GitHub: `java.time.format.Parsed.crossCheck()` line 698: `crossCheck(date.atTime(time));`. `atTme()` returns `null` (one may research why), which causes a `NullPointerException` in `crossCheck(TemporalAccessor)` line 707: `if (target.isSupported(field)) {`. The NPE is caught in `DateTimeFormatter.parse(CharSequence, TemporalQuery)` line 2011: `} catch (RuntimeException ex) {`, from where `createError()` is called. If you can reproduce it in a tiny example with no suspicious circumstances, I think you can report it into the JDK bug system. – Ole V.V. Nov 28 '22 at 06:30
  • @MarkRotteveel the locale is "de_DE". – Lars Wigger Nov 28 '22 at 15:02

1 Answers1

1

We found the problem:

The call was made inside an integration test where LocalDateTime::now was mocked. By default, MockedStatic does not keep the other methods, so things like LocalDateTime::of just return null (very unintuitive design decision imo). Behind the scenes, the parser obviously calls a method by LocalDateTime, resulting in this weird error. Changing Mockito.mockStatic(LocalDateTime.class) to Mockito.mockStatic(LocalDateTime.class, Mockito.CALLS_REAL_METHODS) fixed the problem.