LoginSignup
2
5

More than 5 years have passed since last update.

Java の DateTimeFormatter を使用したときの思わぬ例外

Posted at

まえがき

先日の JJUG CCC 2017 Spring で以下の発表を行いました。

このセッションでの質問で「この10個はどうやって見つけたのですか?」の質問を頂きました。もともと知っていたのと、今回のセッションをやるにあたり見直してみたというのもあるのですが、やはり普段何かしらJavaコアAPIのソースを読んだり何か試してみたりということが地味に効いているのかもと、思いました。

今日の話題

さて、最近以下のことがふと気になったのでやってみました。

Hを多く書いてみる

Q1.PNG

3名の方からご回答頂きました。意見は割れました。私は2番目だと思っていました。
しかし現実は違いました。

A1.PNG

コアAPIの実装を見てみるとこうなっていました。(8u131のソースを抜粋)

DateTimeFormatterBuilder.java(LL.1793-1807)
            case 'd':
            case 'h':
            case 'H':
            case 'k':
            case 'K':
            case 'm':
            case 's':
                if (count == 1) {
                    appendValue(field);
                } else if (count == 2) {
                    appendValue(field, count);
                } else {
                    throw new IllegalArgumentException("Too many pattern letters: " + cur);
                }
                break;

2文字しか受け付けないので3文字以上はアウトということですね。

ではHが2個なら大丈夫か?→場合により例外が出る

そこで次の問題がこれです。

Q2.PNG

これも2番目だと思いました。
しかし現実は違いました。
A2.PNG

これも実装を見てました。

Instant.java(LL.594-606)
    @Override
    public long getLong(TemporalField field) {
        if (field instanceof ChronoField) {
            switch ((ChronoField) field) {
                case NANO_OF_SECOND: return nanos;
                case MICRO_OF_SECOND: return nanos / 1000;
                case MILLI_OF_SECOND: return nanos / 1000_000;
                case INSTANT_SECONDS: return seconds;
            }
            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
        }
        return field.getFrom(this);
    }

今回取得しようとしているHOUR_OF_DAYChronoFieldなので、上記の

        if (field instanceof ChronoField) {

この条件を満たすためこのif文の中に入ってきます。そして、switchの中に該当するフィールドがないのであえなくアウト、ということになります。

つまり、時間を取りたい場合はLocalDateTimeなどHOUR_OF_DAYがサポートされているクラスのインスタンスでないとダメということですね。これは勉強になりました。

付録

テストに使用したコードを載せておきます。個人用に書いたのでコメントもなく、2つのテスト切り替えもコメントを外して実行、といったあまりキレイじゃないやり方でお恥ずかしい。

FormatterTest.java
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 
 */
public class FormatterTest {
    /**
     * 
     * @param arguments 
     */
    public static void main(String[] arguments) {
        //System.out.println(DateTimeFormatter.ofPattern("HH").format(Instant.now()));
        System.out.println(DateTimeFormatter.ofPattern("HHHH").format(LocalDateTime.now()));
    }
}
2
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5