JavaでマスターするDateTimeFormatterのたった7つの方法

JavaでDateTimeFormatterを使った日付と時刻の扱い方Java
この記事は約26分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

日付や時刻は、生活でよく使われる情報であり、プログラミングでも頻繁に使います。

特に、日付や時刻のフォーマットは様々な場面で求められますが、それを簡単に扱うことができるとどれだけ便利か想像してみてください。

この記事では、Javaで使用できるDateTimeFormatterクラスを詳しく解説しています。

この記事を読むことで、日付と時刻の扱い方が一段と簡単になり、より高度な操作も自在に行えるようになるでしょう。

●DateTimeFormatterとは

○Javaでの日付と時刻の重要性

日付と時刻は、ログの生成、スケジューリング、データの有効期限設定など、多くのアプリケーションで必須の要素です。

Javaでこれを扱うためには、いくつかのクラスとメソッドが提供されていますが、その中でDateTimeFormatterは非常に強力なツールです。

○DateTimeFormatterの基本

DateTimeFormatterは、Java 8以降で使用できる日付・時刻APIの一部です。

このクラスを使用すると、非常に簡単に日付や時刻の文字列の生成や解析が行えます。

具体的には、tugi

のような操作が可能です。

  1. 日付や時刻の情報を特定のフォーマットの文字列に変換
  2. 文字列から日付や時刻の情報を解析
  3. ロケール(地域や言語)に基づいたフォーマットの適用

これらの基本的な操作が、DateTimeFormatterを使うメリットとなっています。

●DateTimeFormatterの使い方

日付と時刻のフォーマットは、プログラミングでよく遭遇する課題です。

ここでは、具体的なサンプルコードを交えながら、DateTimeFormatterの使い方について詳しく解説します。

○サンプルコード1:基本的な日付のフォーマット

最初に、シンプルな日付のフォーマットから見ていきましょう。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Main {
  public static void main(String[] args) {
    // 現在の日付を取得
    LocalDate date = LocalDate.now();
    // フォーマッターを作成
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    // 日付をフォーマット
    String formattedDate = date.format(formatter);
    // 出力
    System.out.println("フォーマット後の日付:" + formattedDate);
  }
}

このコードでは、JavaのLocalDateクラスとDateTimeFormatterクラスを利用しています。

まずLocalDate.now()で現在の日付を取得して、その後DateTimeFormatterを使ってフォーマットします。

使用するパターンは”yyyy-MM-dd”で、これにより例えば「2023-09-23」のような形式に日付がフォーマットされます。

このコードを実行すると、実行した日の日付が”yyyy-MM-dd”の形式でコンソールに出力されます。

実行例として、”フォーマット後の日付:2023-09-23″が出力された場合、それは2023年9月23日がその日の日付であるという意味になります。

○サンプルコード2:基本的な時刻のフォーマット

次に、時刻の基本的なフォーマットについて見ていきましょう。

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class Main {
  public static void main(String[] args) {
    // 現在の時刻を取得
    LocalTime time = LocalTime.now();
    // フォーマッターを作成
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
    // 時刻をフォーマット
    String formattedTime = time.format(formatter);
    // 出力
    System.out.println("フォーマット後の時刻:" + formattedTime);
  }
}

このコードではLocalTimeクラスとDateTimeFormatterクラスを使っています。

LocalTime.now()メソッドで現在の時刻を取得した後、”HH:mm:ss”の形式で時刻をフォーマットします。

このコードを実行すると、実行した瞬間の時刻が”HH:mm:ss”の形式で出力されます。

例えば、「フォーマット後の時刻:14:30:15」と出力された場合、それは14時30分15秒がその瞬間の時刻であるという意味になります。

○サンプルコード3:カスタムフォーマットを作成

一歩進んで、オリジナルな日付や時刻のフォーマットを作成する方法について説明します。

例えば、年月日を逆順にしたり、曜日や午前・午後の情報を追加する場合など、独自のフォーマットが求められるケースも少なくありません。

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

public class Main {
  public static void main(String[] args) {
    // 現在の日付と時刻を取得
    LocalDateTime dateTime = LocalDateTime.now();
    // カスタムフォーマッターを作成
    DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm a E");
    // 日付と時刻をカスタムフォーマットで整形
    String customFormattedDateTime = dateTime.format(customFormatter);
    // 出力
    System.out.println("カスタムフォーマット後の日付と時刻:" + customFormattedDateTime);
  }
}

このJavaのコードは、LocalDateTimeDateTimeFormatterを使用しています。

まずLocalDateTime.now()で現在の日付と時刻を取得します。

次に、DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm a E")を使ってカスタムフォーマッターを作成しています。

このパターンでは、日付がdd/MM/yyyy、時刻がhh:mm、午前・午後がa、曜日がEとして表示されます。

コードを実行すると、例えば「カスタムフォーマット後の日付と時刻:23/09/2023 03:15 PM Sat」というような出力が得られます。

これは、2023年9月23日の午後3時15分で、曜日が土曜日であることを示しています。

○サンプルコード4:ロケールによるフォーマットの変更

国や地域によっては、日付や時刻の表示形式が異なることがあります。

Javaでは、このような場合に対応するためにLocaleクラスを使うことができます。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
  public static void main(String[] args) {
    // 現在の日付と時刻を取得
    LocalDateTime dateTime = LocalDateTime.now();
    // ロケールをフランスに設定してフォーマッターを作成
    DateTimeFormatter frenchFormatter = DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy", Locale.FRANCE);
    // 日付と時刻をフランスのロケールでフォーマット
    String frenchFormattedDateTime = dateTime.format(frenchFormatter);
    // 出力
    System.out.println("フランスのロケールでの日付:" + frenchFormattedDateTime);
  }
}

このコードでは、Locale.FRANCEを引数として、DateTimeFormatter.ofPattern("EEEE dd MMMM yyyy", Locale.FRANCE)によってフランス用の日付フォーマットを作成しています。

具体的には、曜日がEEEE、日がdd、月がMMMM、年がyyyyとなるように指定しています。

コードの実行結果を見ると、出力は「フランスのロケールでの日付:samedi 23 septembre 2023」となります。

これがフランスの日付フォーマットに基づいています。

特に、曜日が「samedi」、月が「septembre」とフランス語で表示されている点に注意してください。

○サンプルコード5:時刻帯の指定

日付と時刻の表示では、時刻帯(タイムゾーン)も重要な要素です。

JavaではZoneIdクラスを用いて、特定の地域や都市の時刻帯を指定できます。

ここでは、DateTimeFormatterと組み合わせて時刻帯を指定する方法について詳しく説明します。

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class Main {
  public static void main(String[] args) {
    // 現在の日付と時刻を取得
    LocalDateTime dateTime = LocalDateTime.now();
    // 東京の時刻帯を設定
    ZoneId tokyoZoneId = ZoneId.of("Asia/Tokyo");
    // DateTimeFormatterに時刻帯を設定
    DateTimeFormatter formatterWithZone = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z")
      .withZone(tokyoZoneId);
    // 日付と時刻をフォーマット
    String formattedDateTimeWithZone = formatterWithZone.format(dateTime.atZone(tokyoZoneId));
    // 出力
    System.out.println("東京の時刻帯での日付と時刻:" + formattedDateTimeWithZone);
  }
}

このコードでは、まずZoneId.of("Asia/Tokyo")を用いて、東京の時刻帯オブジェクトを生成しています。

次に、DateTimeFormatter.withZone(tokyoZoneId)を付け加えることで、このフォーマッターが東京の時刻帯を使うように設定されています。

最後に、dateTime.atZone(tokyoZoneId)を用いて、取得した現在の日付と時刻を東京の時刻帯に変換し、その上でフォーマットしています。

コードを実行すると、”東京の時刻帯での日付と時刻:2023-09-23 17:30:45 +0900″ といった出力が得られるでしょう。

ここで+0900はUTCからの時差を表しています。

○サンプルコード6:テキストから日付・時刻への変換

日付や時刻の文字列をプログラムで扱いたい場合も多いでしょう。

DateTimeFormatterを使えば、特定のフォーマットの文字列からLocalDateTimeオブジェクトを簡単に生成できます。

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

public class Main {
  public static void main(String[] args) {
    // フォーマッターを作成
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    // 文字列から日付と時刻を解析
    LocalDateTime parsedDateTime = LocalDateTime.parse("2023-12-25 12:34:56", formatter);
    // 出力
    System.out.println("解析された日付と時刻:" + parsedDateTime);
  }
}

上記のコードでは、DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")で作成したフォーマッターを用いて、文字列"2023-12-25 12:34:56"から日付と時刻を解析しています。

LocalDateTime.parseメソッドにフォーマッターと文字列を渡すことで、解析が行われます。

このコードを実行すれば、”解析された日付と時刻:2023-12-25T12:34:56″ という出力が得られます。

このように、文字列からLocalDateTimeオブジェクトが生成されたことが確認できるでしょう。

○サンプルコード7:エラーハンドリング

日付や時刻のフォーマット、解析作業では、誤った形式の文字列や不正な日付・時刻が与えられた場合に備えて、エラーハンドリングが必要です。

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.LocalDateTime;

public class Main {
  public static void main(String[] args) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String incorrectString = "2023-02-30 12:34:56"; // 閏年でないため、2月30日は存在しない

    try {
      LocalDateTime parsedDateTime = LocalDateTime.parse(incorrectString, formatter);
    } catch (DateTimeParseException e) {
      System.out.println("不正な日付・時刻の形式です:" + e.getMessage());
    }
  }
}

上記のコードではDateTimeParseExceptionをキャッチしています。

"2023-02-30 12:34:56"という、2月30日という存在しない日付をパースしようとすると、この例外が投げられます。

コードを実行すると、「不正な日付・時刻の形式です」というメッセージが表示されるでしょう。

このようにして、不正な入力に対するエラーハンドリングが可能です。

●DateTimeFormatterの応用例

基本的な使い方からエラーハンドリングまで解説してきましたが、更に踏み込んでDateTimeFormatterの応用例をご紹介します。

○サンプルコード8:日付と時刻の計算

まず、日付と時刻の計算についてです。

JavaではLocalDateTimeLocalDateLocalTimeなどのクラスで日付や時刻を簡単に計算できますが、その結果を人が読みやすい形にフォーマットする場合にもDateTimeFormatterが役立ちます。

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

public class Main {
    public static void main(String[] args) {
        // 現在日時の取得
        LocalDateTime now = LocalDateTime.now();
        // 10日後と5時間前の日時を計算
        LocalDateTime futureDate = now.plusDays(10).minusHours(5);

        // DateTimeFormatterで日時を文字列に変換
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedFutureDate = futureDate.format(formatter);

        // 出力する
        System.out.println("計算後の日時: " + formattedFutureDate);
    }
}

このコードでは、LocalDateTime.now()で現在の日時を取得し、その後.plusDays(10).minusHours(5)で10日後、5時間前の日時を計算しています。

そして、DateTimeFormatterを使ってこの計算結果をフォーマットしています。

出力結果は「計算後の日時: 2023-10-03 12:20:45」のようになり、このように日付と時刻の計算結果を整形できます。

○サンプルコード9:複数のフォーマットを扱う

次に、一つの文字列から複数の日時フォーマットを解析する方法です。

DateTimeFormatterofPatternメソッドでパターンを複数指定することができます。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class Main {
    public static void main(String[] args) {
        String[] dateTimeStrings = {
            "2023-10-05",
            "2023-10-05 15:30",
            "2023-10-05T15:30:20"
        };

        for (String dateTimeString : dateTimeStrings) {
            try {
                LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString,
                    DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyy-MM-dd HH:mm][yyyy-MM-dd'T'HH:mm:ss]"));
                System.out.println("解析成功: " + parsedDateTime);
            } catch (DateTimeParseException e) {
                System.out.println("解析失敗: " + e.getMessage());
            }
        }
    }
}

このコードでは、DateTimeFormatter.ofPatternによって複数の日時フォーマットを指定しています。

角括弧[]内に各パターンを記述することで、どのパターンにもマッチするように解析が行われます。

出力結果から、「解析成功: 2023-10-05T00:00」、「解析成功: 2023-10-05T15:30」、「解析成功: 2023-10-05T15:30:20」と表示され、各フォーマットに応じた解析が成功していることがわかります。

○サンプルコード10:外部ライブラリとの連携

最後に、外部ライブラリ、例えばJoda-TimeとDateTimeFormatterを連携させる方法について説明します。

Joda-TimeはJava 8より前に広く使われていた日時操作ライブラリですが、既存のプロジェクトで使われている場合もあるでしょう。

import org.joda.time.format.DateTimeFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // Java 8のDateTimeFormatter
        DateTimeFormatter java8Formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // Joda-TimeのDateTimeFormatter
        org.joda.time.format.DateTimeFormatter jodaFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

        // Joda-TimeのDateTimeFormatterをJava 8のDateTimeFormatterに変換
        DateTimeFormatter convertedFormatter = DateTimeFormatter.ofPattern(jodaFormatter.toString());

        LocalDateTime dateTime = LocalDateTime.now();
        String formattedDate = dateTime.format(convertedFormatter);
        System.out.println("フォーマットされた日時: " + formattedDate);
    }
}

このコードでは、Joda-TimeのDateTimeFormatterのパターン文字列をtoString()メソッドで取得し、それをDateTimeFormatter.ofPatternに渡してJava 8のDateTimeFormatter`を生成しています。

これによって、Joda-Timeで使っていた日時フォーマットをJava 8にスムーズに移行できます。

出力結果は「フォーマットされた日時: 2023-10-05 16:45:30」のように、Java 8のDateTimeFormatterで正確に日時がフォーマットされることが確認できます。

●注意点と対処法

JavaのDateTimeFormatterを使う上での注意点や問題点を総括し、それに対する対処法を解説します。

確かにDateTimeFormatterは非常に便利な機能を提供していますが、使用する上で把握しておくべきいくつかの要点があります。

○年月日の範囲とバリデーション

DateTimeFormatterを使用する際、年月日の範囲やバリデーションを確認する重要性があります。

たとえば、閏年や月の日数などを考慮する必要があります。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class Main {
    public static void main(String[] args) {
        String input = "2023-02-30";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        try {
            LocalDate date = LocalDate.parse(input, formatter);
            System.out.println("成功: " + date);
        } catch (DateTimeParseException e) {
            System.out.println("失敗: " + e.getMessage());
        }
    }
}

このコードは2023年2月30日という存在しない日付をパースしようとしています。

この場合、DateTimeParseExceptionがスローされ、「失敗: Text ‘2023-02-30’ could not be parsed: Invalid date ‘February 30’」というエラーメッセージが表示されます。

○ロケールに依存する問題

日本以外の国や地域で使用される日付形式や曜日、月名などを適切に扱うためには、ロケールの指定が必要です。

import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy", Locale.US);
        System.out.println(formatter.format(LocalDate.now()));
    }
}

このコードはアメリカの日付形式(例:January 01, 2023)で現在の日付を出力します。

出力結果としては、例えば「October 10, 2023」が表示されるでしょう。

○スレッドセーフ性

DateTimeFormatterはイミュータブルな設計であり、そのためスレッドセーフです。

この点は特に対処が必要ないのですが、DateTimeFormatterを適用するデータ自体がスレッドセーフでない場合は注意が必要です。

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

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        Runnable formatTask = () -> {
            LocalDateTime dateTime = LocalDateTime.now();
            String result = dateTime.format(formatter);
            System.out.println("スレッドセーフ: " + result);
        };

        Thread t1 = new Thread(formatTask);
        Thread t2 = new Thread(formatTask);

        t1.start();
        t2.start();
    }
}

このコードはマルチスレッド環境でDateTimeFormatterが正しく動作するかを確認するシンプルな例です。

ここではRunnableインタフェースを用いてスレッドを2つ起動しています。

各スレッドが異なるタイムスタンプを出力しますが、DateTimeFormatter自体はスレッドセーフであるため問題は発生しません。

●カスタマイズ方法

JavaでDateTimeFormatterを使いこなすためには、さまざまなカスタマイズが可能です。

ここでは、基本的なフォーマットパターンの詳細から、より高度なカスタマイズ手法までをご紹介します。

○フォーマットパターンの詳細

JavaのDateTimeFormatterでは、特定のフォーマットパターンを指定して日付や時刻を整形することができます。

このフォーマットパターンにはいくつかの文字列があります。

例えば、yyyyで年、MMで月、ddで日、HHで24時間制の時、mmで分を表します。

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

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        LocalDateTime now = LocalDateTime.now();
        String formattedDate = now.format(formatter);
        System.out.println(formattedDate);
    }
}

このコードではDateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")を用いて、年月日と時刻を2023/09/23 15:45:30のような形に整形しています。

出力結果としては、2023/09/23 15:45:30のような現在日時が表示されます。

○DateTimeFormatterBuilderを使った高度なカスタマイズ

基本的なフォーマットパターンでも多くのことができますが、更に高度なカスタマイズが必要な場合はDateTimeFormatterBuilderを使用します。

このクラスを使用すると、オプショナルな部分を含めたり、特定の条件下で異なるフォーマットを適用したりできます。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
        builder.append(DateTimeFormatter.ISO_LOCAL_DATE)
               .appendLiteral(" ")
               .appendValue(ChronoField.HOUR_OF_DAY, 2)
               .appendLiteral(":")
               .appendValue(ChronoField.MINUTE_OF_HOUR, 2);

        DateTimeFormatter formatter = builder.toFormatter();
        LocalDateTime now = LocalDateTime.now();
        String formattedDate = now.format(formatter);
        System.out.println(formattedDate);
    }
}

上記のコードでは、DateTimeFormatterBuilderを用いて高度なカスタマイズを行っています。

まず、ISO形式のローカル日付(例:2023-09-23)を追加し、その後に時間(例:15)と分(例:45)を追加しています。

この結果、2023-09-23 15:45のようなフォーマットになります。

まとめ

この記事ではJavaで日付や時刻を扱う際の最適な手段として、DateTimeFormatterに焦点を当てました。

基本的な使い方から、より高度なカスタマイズ方法までを網羅的に解説してきました。

このように、DateTimeFormatterはJavaで日付と時刻を扱う際の多くの問題を解決してくれる優れたツールです。

習得しておけば、多くのプロジェクトでその恩恵を受けることができるでしょう。

この記事が、DateTimeFormatterの全体像を把握し、実用的なスキルを身につける一助となれば幸いです。