title: Define a custom date format and converter with Spring Data Elasticsearch
body: <p>I'm currently migrating from Spring Data Elasticsearch 3.2.x to 4.0.0.</p>
  
  <p>I'm removing a <code>JacksonEntityMapper</code>, that defined a custom <code>ZonedDateTimeDeserializer</code>, to use the <code>ElasticsearchEntityMapper</code></p>
  
  <p>I have a ZonedDateTime field defined as follows:</p>
  
  <pre><code>    @Field(type = Date, format = DateFormat.date_time)
      private final ZonedDateTime loggedIn;
  </code></pre>
  
  <p>However, the deserialization of this loses the zone information, so that a comparison between the field before and after being stored fails:</p>
  
  <p>before</p>
  
  <pre><code>loggedIn=2020-06-01T09:50:27.389589+01:00[Europe/London]
  </code></pre>
  
  <p>after</p>
  
  <pre><code>loggedIn=2020-06-01T09:50:27.389+01:00
  </code></pre>
  
  <p>I expect the zone information to be lost as only the timezone offset is being stored. With the Jackson <code>ZonedDateTimeDeserializer</code> I was able to apply the Zone during the ZonedDateTime construction.</p>
  
  <p>Ideally, I'd like to define a custom date format and converter classes to handle my scenario.</p>
  
  <p>I've tried the following field configuration:</p>
  
  <pre><code>    @Field(type = Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ")
      private final ZonedDateTime loggedIn;
  </code></pre>
  
  <p>With Reading/WritingConverters</p>
  
  <pre><code>@WritingConverter
  public class ZonedDateTimeToStringConverter implements Converter&lt;ZonedDateTime, String&gt;  {
  
      @Override
      public String convert(ZonedDateTime source) {
          return source.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
      }
  }
  
  @ReadingConverter
  public class StringToZonedDateTimeConverter implements Converter&lt;String, ZonedDateTime&gt;  {
  
      @Override
      public ZonedDateTime convert(String source) {
          return ZonedDateTime.parse(source, DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.systemDefault()));
      }
  }
  </code></pre>
  
  <p>and configuration</p>
  
  <pre><code>public class ElasticConfiguration extends AbstractElasticsearchConfiguration {
  
      @Bean
      @Override
      public ElasticsearchCustomConversions elasticsearchCustomConversions() {
          return new ElasticsearchCustomConversions(List.of(new ZonedDateTimeToStringConverter(),
                                                            new StringToZonedDateTimeConverter()));
      }
  }
  </code></pre>
  
  <p>However, the reading of the field fails with an exception</p>
  
  <pre><code>Caused by: java.time.DateTimeException: Unable to obtain LocalDate from TemporalAccessor: {YearOfEra=2020, MonthOfYear=8, DayOfMonth=20, OffsetSeconds=3600},ISO resolved to 11:11:11.123 of type java.time.format.Parsed
      at java.base/java.time.LocalDate.from(LocalDate.java:396)
      at java.base/java.time.ZonedDateTime.from(ZonedDateTime.java:560)
      at org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter.parse(ElasticsearchDateConverter.java:109)
      at org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter.parse(ElasticsearchDateConverter.java:114)
      ...
  </code></pre>
  
  <p>Looking at the exception, when comparing the parsing against the successful <code>DateFormat.date_time</code> read, I may have an error in the pattern. The TemporalAccessor for the <code>DateFormat.date_time</code> is <code>{OffsetSeconds=3600, InstantSeconds=1597918271},ISO resolved to 2020-08-20T11:11:11.123</code>, whereas my custom pattern parses to <code>{YearOfEra=2020, MonthOfYear=8, DayOfMonth=20, OffsetSeconds=3600},ISO resolved to 11:11:11.123</code></p>
  
  <p>But it also seems that the custom converters I specified aren't being picked up. Note. I have other customer converters specified that are being picked up so don't believe it's a configuration issue.</p>
  
  <p>Any help would be appreciated, I'm not sure why the custom pattern fails, but think I could avoid it if the custom converters were picked up. I can workaround the issue for now, but ideally I'd like everything to be consistent before and after the upgrade.</p>