---
title: Spring MVCの@DateTimeFormatで和暦パターンを扱う方法
tags: ["Spring MVC", "Java"]
categories: ["Programming", "Java", "org", "springframework", "web"]
date: 2016-03-03T04:38:19Z
updated: 2016-03-03T04:38:19Z
---

Spring MVCでリクエストパラメータをバインドする場合は`@DateTimeFormat`でパターンを指定しますが、
和暦フォーマット(`GGGGyy.MM.dd`など)を指定するとパースエラーが発生します。

和暦を扱う場合はパーサーに`Locale`や`Chronology`を指定する必要があるのですが、
当然ながら日本用のものは指定されていないため、パースエラーとなります。

実はパーサーが使う`Locale`や`Chronology`は、`org.springframework.context.i18n.LocaleContextHolder`や`org.springframework.format.datetime.standard.DateTimeContextHolder`を使ってスレッドローカルに保存できます。
なのでFilterやInterceptorでこれを指定してやればOKです。

`HandlerInterceptorAdapter`を使う例を以下に示します。

``` java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.datetime.standard.DateTimeContext;
import org.springframework.format.datetime.standard.DateTimeContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.chrono.JapaneseChronology;
import java.util.Date;
import java.util.Locale;

@SpringBootApplication
@RestController
public class DemoWarekiApplication extends WebMvcConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(DemoWarekiApplication.class, args);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        DateTimeContext context = new DateTimeContext();
        context.setChronology(JapaneseChronology.INSTANCE);
        Locale japan = new Locale("ja", "JP", "JP");

        registry.addInterceptor(new HandlerInterceptorAdapter() {
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                DateTimeContextHolder.setDateTimeContext(context); // for java.time.LocalDate
                LocaleContextHolder.setLocale(japan); // for java.util.Date
                return true;
            }
        });
    }

    @RequestMapping(path = "/jud")
    Object jud(@DateTimeFormat(pattern = "GGGGyy.MM.dd") @RequestParam(name = "date") Date date) {
        return date.toString();
    }

    @RequestMapping(path = "/jtl")
    Object jtl(@DateTimeFormat(pattern = "GGGGyy.MM.dd") @RequestParam(name = "date") LocalDate date) {
        return date.toString();
    }
}
```

アクセス例

``` console
$ curl "localhost:8080/jud?date=平成28.03.03"
Thu Mar 03 00:00:00 JST 2016
$ curl "localhost:8080/jtl?date=平成28.03.03"
2016-03-03
```

https://jira.spring.io/browse/SPR-13568
