java-beginner.com ブログ

プログラミングを学習するブログ(Javaをメインに)

Date-Time APIで月末を取得する。

投稿日:

最終更新日:2016年07月28日

アイキャッチ

こんにちは。「Javaを復習する初心者」です。

今回はJava8の機能であるDate-Time APIを使って、月末を取得する方法を書きました。

きっかけ

以前、「Calendarで月末を取得」という記事を書いた時、以下の2つの方法を使いました。

  1. getActualMaximumメソッドを使う。
  2. 翌月初日から-1日する。

この方法をJava8のDate-Time APIで用意されているLocalDateクラスに書き直そうとしました。2月の末日を取得する方法です。それが以下の2つです。

  1. LocalDate.of(2016, Month.FEBRUARY.getValue(), 1).range(ChronoField.DAY_OF_MONTH).getMaximum()
  2. LocalDate.of(2016, Month.MARCH.getValue(), 1).minusDays(1L).getDayOfMonth()

実はlengthOfMonth()メソッドがあるのにその存在を気づかずに、上記の方法で速さを比較し、Qiitaに投稿しました。

https://qiita.com/java-beginner/items/e970a3d75de44413ab09

その結果、コメントを頂き、「lengthOfMonth()」メソッドを教えていただきました。このメソッドで月末が取得できるのでした。また、LocalDateクラスは年月日を設定して使うのですが、java.time.YearMonthというクラスがあり、こちらは年月の設定で使えることも教えていただきました。

後で気づいたのですが、LocalDate.of()は第2引数の指定でgetValueは必要ないようです。

上記のいきさつにより、Java8では月末取得は以下の2つの方法どちらかだと思います。

  1. LocalDate.of(2016, Month.FEBRUARY, 1).lengthOfMonth()
  2. YearMonth.of(2016, Month.FEBRUARY).lengthOfMonth()

速さ比較

前回のCalendarクラスで実行したメソッドも含め、比較してみました。100000回繰り返した時間を計測しました。

ソースコード

package dataTimeApiTest;

import java.time.LocalDate;
import java.time.Month;
import java.time.YearMonth;
import java.time.temporal.ChronoField;
import java.util.Calendar;

public class HelloLastDay {

    public static void main(String[] args) {

        int loopCount = 100000;
        long startTime, endTime;

        System.out.println("java7 getActualMaximum");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            java7_1();
        }
        endTime   = System.currentTimeMillis();
        System.out.println(endTime - startTime);

        System.out.println("java7 翌月初日-1");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            java7_2();
        }
        endTime   = System.currentTimeMillis();
        System.out.println(endTime - startTime);

        System.out.println("java8 rangeを使う");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            java8_1();
        }
        endTime   = System.currentTimeMillis();
        System.out.println(endTime - startTime);

        System.out.println("java8 翌月初日-1");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            java8_2();
        }
        endTime   = System.currentTimeMillis();
        System.out.println(endTime - startTime);

        System.out.println("LocalDate.of(2016, Month.FEBRUARY, 1).lengthOfMonth()");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            java8_3();
        }
        endTime   = System.currentTimeMillis();
        System.out.println(endTime - startTime);

        System.out.println("YearMonth.of(2016, Month.FEBRUARY).lengthOfMonth()");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < loopCount; i++) {
            java8_4();
        }
        endTime   = System.currentTimeMillis();
        System.out.println(endTime - startTime);

    }

    private static void java7_1() {
        Calendar c = Calendar.getInstance();
        c.clear();
        c.set(2016, 1, 1);
        c.getActualMaximum(Calendar.DATE);

    }

    private static void java7_2() {
        Calendar c = Calendar.getInstance();
        c.clear();
        c.set(2016, 2, 1);
        c.add(Calendar.DATE, -1);
        c.get(Calendar.DATE);
    }

    private static void java8_1() {
        long lastDay = LocalDate.of(2016, Month.FEBRUARY.getValue(), 1).range(ChronoField.DAY_OF_MONTH).getMaximum();
    }

    private static void java8_2() {
        long lastDay = LocalDate.of(2016, Month.MARCH.getValue(), 1).minusDays(1L).getDayOfMonth();
    }

    private static void java8_3() {
        long lastDay = LocalDate.of(2016, Month.FEBRUARY, 1).lengthOfMonth();
    }

    private static void java8_4() {
        long lastDay = YearMonth.of(2016, Month.FEBRUARY).lengthOfMonth();
    }

}

結果

java7 getActualMaximum
472
java7 翌月初日-1
300
java8 rangeを使う
92
java8 翌月初日-1
46
LocalDate.of(2016, Month.FEBRUARY, 1).lengthOfMonth()
6
YearMonth.of(2016, Month.FEBRUARY).lengthOfMonth()
28

上記結果を見ると、LocalDate.of(2016, Month.FEBRUARY, 1).lengthOfMonth()が速いです。