Java
2022.08.25
Javaで日付をフォーマットする方法!SimpleDateFormatを使いこなそう
2023.11.18

日付にはさまざまな表現方法があります。


年月日を表すだけでも「2022/2/1」「2022/02/01」「2022年2月1日」など幅があり、これに曜日、時間を足す表現も考えられますよね。


場合によって適切な表現ができるよう、日付のフォーマットについて学んでいきましょう。


1.Javaで日付をフォーマットする方法

Javaで日付のフォーマットを行うには、SimpleDateFormatクラスを使用します。


SimpleDateFormatクラスを使ったフォーマットの大まかな手順を見てみましょう。

  1. SimpleDateFormatクラスをインポート
  2. フォーマットしたい日付を取得
  3. インスタンスの生成時にパターンを指定
  4. 3で作成したインスタンスで日付をフォーマット

これをコードで記述すると以下のようになります。

import java.text.SimpleDateFormat; // 1.インポート
import java.util.Date;

public class Java_dateformat {
    public static void main(String[] args) {
        Date exDate = new Date();   // 2.日付(今回は現在の日時)を取得
        SimpleDateFormat exDateFormat = new SimpleDateFormat("yyyy/MM/dd"); // 3.パターンを指定

        System.out.println(exDateFormat.format(exDate)); // 4.日付をフォーマットし出力
    }
}

出力:

2022/03/04

目的に応じて


・どんな日付を扱うのか

・どんなフォーマットのパターンを指定するのか

などの違いはありますが、基本的な流れは上記の通りです。

以降でSimpleDateFormatクラスの使い方、パターン文字列の表現方法を学びながら、手順を理解していきましょう。



2.SimpleDateFormatクラスの基本


まずはSimpleDateFormatクラスの基本的な使い方を解説します。

①日時パターン文字列

SimpleDateFormatクラスで使われる日時パターン文字列を見てみましょう。これを組み合わせることで任意のパターンを表現できます。

文字意味出力例
G紀元G:西暦 G:R、Hなどの略称(LocaleのバリアントがJPのとき)
GGGG:令和、平成など(LocaleのバリアントがJPのとき)
yy:2022年→2022
yy:2022年→22
yyy:2022年→2022
暦週の基準年Y:2022年→2022
YY:2022年→22
YYY:2022年→2022
M年における月(状況依存)M:3月→3
MM:3月→03
MMM:3月→3月
L年における月(スタンドアロン形式)L:3月→3
LL:3月→03
LLL:3月→3月
w年における週w:3月4日→10
ww:3月4日→10
www:3月4日→010
wを増やすとその分0埋め
W月における週W:3月4日→1
WW:3月4日→01
WWW:3月4日→001
Wを増やすとその分0埋め
D年における日D:3月4日→63
DD:3月4日→63
DDD:3月4日→063
Dを増やすとその分0埋め
d月における日d:3月4日→4
dd:3月4日→04
ddd:3月4日→004
dを増やすとその分0埋め
F月における曜日F:3月4日→1
FF:3月4日→01
FFF:3月4日→001
Fを増やすとその分0埋め
E曜日の名前E:3月4日(金)→金
EEEE:3月4日(金)→金曜日
u曜日の番号(1 =月曜、…、7 =日曜)u:3月4日(金)→5
uu:3月4日(金)→05
uuu:3月4日(金)→005
uを増やすとその分0埋め
a午前/午後a:9:20→AM
H一日における時(0 – 23)H:0:20→0
HH:0:20→0
HHH:0:20→000
Hを増やすとその分0埋め
k一日における時(1 – 24)k:0:20→24
kk:0:20→24
kkk:0:20→024
kを増やすとその分0埋め
K午前/午後の時(0 – 11)K:12:20→0
KK:12:20→00
KKK:12:20→000
Kを増やすとその分0埋め
h午前/午後の時(1 – 12)h:12:20→12
hh:12:20→12
hhh:12:20→12
hを増やすとその分0埋め
mm:9:20→20
mm:9:20→20
mmm:9:20→020
mを増やすとその分0埋め
ss:9:20:40→40
ss:9:20:40→40
sss:9:20:40→040
sを増やすとその分0埋め
Sミリ秒S:9:20:40.110→110
SS:9:20:40.110→110
SSS:9:20:40.110→110
Sを増やすとその分0埋め
z一般的なタイムゾーンz:日本標準時→JST
zzzz:日本標準時→日本標準時
ZRFC 822タイムゾーンZ:日本標準時→+0900
XISO 8601タイムゾーンX:日本標準時→+09
XX:日本標準時→+0900
XXX:日本標準時→+09:00

この中でよく使われるのは、y(年)、M(年における月)、d(月における日)です。時間を表す場合にはH(0-23の時間)、m(分)もよく使われます。


文字をいくつ重ねるかによって表示方法が変わるので注意してください。

②コンストラクタ

SimpleDateFormatクラスにはコンストラクタがいくつかあります。つまり、場合によってインスタンスの生成方法を変えられるということです。それぞれどのようなときに使われるのか、ひとつずつ見ていきましょう。

SimpleDateFormat()

引数のないタイプです。


デフォルトの「yyyy/MM/dd HH:mm」パターンでインスタンスが生成されます。

一般的な形で年月日と時間を表したいだけの場合、このコンストラクタを使うと便利です。

SimpleDateFormat(String pattern)

引数がパターン文字列のみのタイプです。


先ほど紹介した日時パターン文字列を組み合わせて引数に指定し、デフォルトの日付フォーマット記号を使ってインスタンスを生成できます。


日付フォーマット記号を変更する必要が無く、フォーマットしたいパターンがある場合に使われます。

SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)

引数がパターン文字列、日付フォーマット記号のタイプです。

日時パターン文字列を組み合わせたもの、日付フォーマット記号を両方指定してインスタンスを生成できます。


しかし、日付フォーマット記号を指定してインスタンス化することはあまりありません。次に紹介する、ロケールを指定するコンストラクタの方がよく使われます。

SimpleDateFormat(String pattern, Locale locale)

引数がパターン文字列、ロケールのタイプです。

ロケールとは日付を表すときに使う言語のことです。タイムゾーンとは違うものなので注意しましょう。


日時パターン文字列を組み合わせたものと、ロケールを両方指定してインスタンスを生成できます。指定したロケールのデフォルト日付フォーマット記号が自動的に使われます。


ロケールを別の国のものに変更し、フォーマットしたいパターンがある場合に使うと便利です。

③便利なメソッド

次に、SimpleDateFormatクラスに使用できる便利なメソッドを紹介します。

 formatメソッド

formatメソッドは、指定されたDateをパターン文字列にフォーマットするときに使います。

基本的な構文は以下の通りです。

SimpleDateFormatのインスタンス名.format(Dateのインスタンス名)

実際の使い方を見ていきましょう。

import java.text.SimpleDateFormat;
import java.util.Date;

public class Sdf_format {
    public static void main(String[] args) {
        Date now = new Date(); // Dateのインスタンス"now"を生成
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm XXX"); // パターンを指定し、SimpleDateFormatのインスタンス"dateFormat"を生成

        String formatted = dateFormat.format(now); // formatメソッドでフォーマット

        System.out.println(formatted);
    }
}

出力:

2022/03/04 10:35 +09:00

コードは最初に紹介したサンプルとほとんど同じものです。formatメソッドに関係する箇所にコメントを入れました。


大まかにはDate、SimpleDateFormatのインスタンスをそれぞれ生成しておき、formatメソッドでフォーマットする、という流れです。


フォーマットする際には欠かせないメソッドなので、覚えておきましょう。

 setTimeZoneメソッド

setTimeZoneメソッドは、simpleDateFormatオブジェクトのタイムゾーンを設定します。


基本的な構文は以下の通りです。

simpleDateFormatのインスタンス名.setTimeZone(TimeZone.getTimeZone("タイムゾーンID"))

実際の使い方を見ていきましょう。

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone; // TimeZoneのインポート

public class Sdf_setTimeZone {
    public static void main(String args[]) {
        Date now = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm XXX"); // パターンを指定し、SimpleDateFormatのインスタンス"dateFormat"を生成

        System.out.println("タイムゾーン設定前              :" + dateFormat.format(now));

        dateFormat.setTimeZone(TimeZone.getTimeZone("US/Eastern")); // setTimeZoneでタイムゾーンを設定

        System.out.println("タイムゾーンをUS/Easternに設定後:" + dateFormat.format(now));
    }
}

出力:

タイムゾーン設定前              :2022/03/04 10:35 +09:00
タイムゾーンをUS/Easternに設定後:2022/03/03 20:35 -05:00

先ほどと同じように、生成したSimpleDateFormatのインスタンスに対してsetTimeZoneメソッドを使うことで、タイムゾーンを設定できます。


setTimeZoneの引数にはTimeZoneを与える必要があります。つまり「TimeZone.getTimeZone(“US/Eastern”)」の部分でタイムゾーンIDを指定したTimeZoneを取得して、引数として使っているのです。


タイムゾーンを設定したあとのインスタンスに対してフォーマットを行うと、しっかり反映されていることがわかります。

 parseメソッド

parseは、文字列をDateに変換するメソッドです。

基本的な構文は以下の通りです。

SimpleDateFormatのインスタンス名.parse(変換したい日時文字列)

実際の使い方を見ていきましょう。

import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException; // 解析に失敗したときの戻り値はParseException

public class Sdf_parse {
    public static void main(String args[]) {
        try {
            String str = "2022/03/04 10:35 +09:00";
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm XXX"); // パターンを指定し、SimpleDateFormatのインスタンス"dateFormat"を生成

            Date date = dateFormat.parse(str); // parseでSimpleDateFormatをDateに変換

            System.out.println(date);
        } catch (ParseException e) { // 解析に失敗したときは例外が発生
            e.printStackTrace();
        }
    }
}

出力:

Fri Mar 04 10:35:00 JST 2022

parseメソッドでは、変換したい文字列と、その文字列のパターンと一致するSimpleDateFormatのインスタンスが必要です。そのインスタンスをもとに文字列を解析し、Dateを返します。


また、解析が失敗したときは戻り値としてParseExceptionが返ってくるため、インポートを忘れないようにしましょう。try-catch文などで例外処理を行わないとエラー(Unhandled Exception)が起こることにも注意してください。

④サンプルソース

これまで紹介したSimpleDateFormatの基本について、改めてサンプルコードを見て確認しましょう。

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.text.ParseException;
import java.util.Locale;

public class Sdf_sample {
    public static void main(String args[]) {
        Date now = new Date();
        Locale locale = new Locale("en"); // 英語のロケール構築

        System.out.println("--------------");

        /*-------コンストラクタを使う-------*/

        // 引数なし
        SimpleDateFormat dateFormat0 = new SimpleDateFormat();

        // パターン文字列のみ指定
        SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy/MM/dd(EEEE) HH:mm XXX");

        // パターン文字列、既に構築してあるロケールを指定
        SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy/MM/dd(EEEE) HH:mm XXX", locale);

        // パターン文字列、ロケールをメソッド内で直接指定
        SimpleDateFormat dateFormat2d = new SimpleDateFormat("yyyy/MM/dd(EEEE) HH:mm XXX", Locale.ENGLISH);

        // フォーマットして出力してみる
        System.out.println("引数なしの場合                          :" + dateFormat0.format(now));
        System.out.println("引数がパターン文字列のみ                :" + dateFormat1.format(now));
        System.out.println("パターン文字列、ロケールを指定          :" + dateFormat2.format(now));
        System.out.println("パターン文字列、ロケールを直接指定      :" + dateFormat2d.format(now));

        /*--------------------------------*/

        System.out.println("--------------");

        /*--様々なパターン文字列を指定する--*/
        // パターン文字列の指定
        SimpleDateFormat dateFormat11 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        SimpleDateFormat dateFormat12 = new SimpleDateFormat("yyyy年MM月dd日 HH時mm分ss秒");

        // フォーマットして出力してみる
        System.out.println("yyy/MM/dd HH:mm:ss          :" + dateFormat11.format(now));
        System.out.println("yyyy年MM月dd日 HH時mm分ss秒 :" + dateFormat12.format(now));
        /*--------------------------------*/

        System.out.println("--------------");

        /*---------formatメソッド---------*/
        // formatメソッドでフォーマット
        String formatted = dateFormat1.format(now);

        // フォーマットした文字列を出力
        System.out.println("formatメソッド      :" + formatted);
        /*--------------------------------*/

        System.out.println("--------------");

        /*-------setTimeZoneメソッド------*/
        // setTimeZoneメソッドでタイムゾーンを設定
        dateFormat1.setTimeZone(TimeZone.getTimeZone("US/Eastern")); // setTimeZoneでタイムゾーンを設定

        // タイムゾーンを設定したsimpleDateFormatでフォーマットし、出力
        System.out.println("setTimeZoneメソッド :" + dateFormat1.format(now));
        /*--------------------------------*/

        System.out.println("--------------");

        /*----------parseメソッド---------*/
        try {
            String str = "2022/03/04(金曜日) 10:35 +09:00";

            // parseでSimpleDateFormatをDateに変換
            Date date = dateFormat1.parse(str);

            // 変換したDateを出力
            System.out.println("parseメソッド       :" + date);
        } catch (ParseException e) { // 解析に失敗したときは例外が発生
            e.printStackTrace();
        }
        /*--------------------------------*/
	System.out.println("--------------");
    }
}

出力:

--------------
引数なしの場合                          :2022/03/04 10:35
引数がパターン文字列のみ                :2022/03/04(金曜日) 10:35+09:00
パターン文字列、ロケールを指定          :2022/03/04(Friday) 10:35 +09:00
パターン文字列、ロケールを直接指定      :2022/03/04(Friday) 10:35 +09:00
--------------
yyy/MM/dd HH:mm:ss          :2022/03/04 10:35:35
yyyy年MM月dd日 HH時mm分ss秒 :2022年03月04日 10時35分35秒
--------------
formatメソッド      :2022/03/04(金曜日) 10:35 +09:00
--------------
setTimeZoneメソッド :2022/03/04(木曜日) 20:35 -05:00
--------------
parseメソッド       :Fri Mar 04 10:35:00 JST 2022
--------------

サンプルコードを実行すると、上のような出力が得られます。

それぞれの出力の違いを見比べてみてください。



3.Date型とString型の日付を相互変換する方法

Date型を扱いやすいString型に変更したいこともあれば、先ほど紹介したようなメソッドを使うためにString型をDate型に変換したいこともあります。


それぞれの変換方法を見ていきましょう。

①    Date型→String型に変換

Date型をString型に変換するには、String型のvalueOfメソッドか、先ほど紹介したformatメソッドを使います。


まずvalueOfメソッドの使い方を見てみましょう。

String.valueOf(変換したいDate型)

valueOfメソッドのカッコ内に変換したいDate型を指定して使います。

このメソッドでDate型を変換する場合、戻り値のString型はDate型をそのまま出力したときと同じ文字列になります。


次にformatメソッドを見てみましょう。

SimpleDateFormatのインスタンス名.format(変換したいDate型)

こちらの使い方はすでに紹介しています。先に解説した通り使えば問題ありません。

このメソッドでDate型を変換する場合、SimpleDateFormatインスタンスによってフォーマットを指定してString型にできます。


このふたつの方法を実際に使ってみると、以下のようになります。

import java.text.SimpleDateFormat;
import java.util.Date;

public class DateToString {
    public static void main(String args[]) {
        Date now = new Date(); // 現在の日時でDate型を取得

        System.out.println("変換するDate型  :" + now); // Date型をそのまま出力

        // valueOfでDate型->String
        String str1 = String.valueOf(now); // valueOfの戻り値をstr1に格納
        System.out.println("valueOfで変換   :" + str1); // str1を出力

        // formatでDate型->String
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd(EEEE) HH:mm XXX"); // パターンを指定し、SimpleDateFormatのインスタンス"dateFormat"を生成
        String str2 = dateFormat.format(now); // formatの戻り値をstr2に格納
        System.out.println("formatで変換    :" + str2); // str2型を出力
    }
}

出力:

変換するDate型  :Fri Mar 04 10:35:35 JST 2022
valueOfで変換   :Fri Mar 04 10:35:35 JST 2022
formatで変換    :2022/03/04(金曜日) 10:35 +09:00

前述の通り、valueOfを使うとDate型をそのまま出力したときと同じ文字列になります。そのままで良ければvalueOfを、任意のフォーマットで変換したい場合にはformatメソッドというように使い分けましょう。

②    String型→Date型に変換

String型をDate型に変換するには、先ほど紹介したparseメソッドを使います。

簡単に使い方を見ていきましょう。

SimpleDateFormatのインスタンス名.parse(変換したい日時文字列)

変換したい文字列をカッコ内に指定することで、Date型に変換できます。メソッド紹介ですでに解説しているので、詳しくはそちらをご覧ください。


実際の使用例を見てみましょう。

import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException; // 解析に失敗したときの戻り値はParseException

public class StringToDate {
    public static void main(String args[]) {
        try {
            String str = "2022/03/04(金曜日) 10:35 +09:00"; // 変換したい文字列
            System.out.println("変換前の文字列  :" + str);

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd(EEEE) HH:mm XXX"); // パターンを指定し、SimpleDateFormatのインスタンス"dateFormat"を生成

            Date date = dateFormat.parse(str); // parseでSimpleDateFormatをDateに変換

            System.out.println("parseで変換  :" + date);  // dateを出力
        } catch (ParseException e) { // 解析に失敗したときは例外が発生
            e.printStackTrace();
        }
    }
}

出力:

変換前の文字列  :2022/03/04(金曜日) 10:35 +09:00
parseで変換  :Fri Mar 04 10:35:35 JST 2022

String型をDate型に変換すれば、タイムゾーンを設定したり、別のフォーマットで出力し直したり、さまざまなことが簡単にできます。方法を覚えておくととても便利です。



4.日付のパターンをチェックする方法


parseメソッドなどで指定する日付文字列が正しいかを厳密にチェックしたいときには、setLenientメソッドをfalseに設定します。


使い方は以下の通りです。

simpleDateFormatのインスタンス名.setLenient(false)

setLenientメソッドを使用する際にはfalseかtrueのどちらかを指定でき、通常の状態ではtrueになっています。


これがtrueのとき、日付の正しさを厳密にはチェックしません。例えば、日付の文字列と指定したパターンの形が違えば例外が発生しますが、日付文字列がもし存在しない日付だったとしても例外は発生しません。



存在しない日付のままparseメソッドを使うと、自動的に余った日付の分進めてDate型に変換されます。例えば「6/31」でparseを行ったならば、「6/30」の次の日の「7/1」などです。


反対にこれがfalseのときには、日付の正しさが厳密にチェックされます。例えば、日付文字列の形の違いだけではなく、存在しない日付(6/31など)であっても例外が発生します。


使用例を見てみましょう。

import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;

public class Check_setLenient {
    public static void main(String args[]) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd(EEEE)"); // パターンを指定し、SimpleDateFormatのインスタンス"dateFormat"を生成
        String str = "2022/06/16(木曜日)";
        String str1 = "2022/06/16()";
        String str2 = "2022/06/31(金曜日)";

        /*----setLenientがtrue(通常)のとき----*/
        System.out.println("setLenientがtrue(通常)のとき");
        try {// 形も日付も正しい文字列のとき
            dateFormat.parse(str);
            System.out.println("2022/06/16(木曜日)  :OK");
        } catch (ParseException e) {
            System.out.println("2022/06/16(木曜日)  :NG");
        }

        try {// 形が間違っている文字列のとき
            dateFormat.parse(str1);
            System.out.println("2022/06/16()        :OK");
        } catch (ParseException e) {
            System.out.println("2022/06/16()        :NG");
        }

        try {// 存在しない日付が文字列のとき
            dateFormat.parse(str2);
            System.out.println("2022/06/31(金曜日)  :OK");
        } catch (ParseException e) {
            System.out.println("2022/06/31(金曜日)  :NG");
        }
        /*-------------------------------------*/

        /*-------setLenientがfalseのとき-------*/
        System.out.println("setLenientがfalse(通常)のとき");
        dateFormat.setLenient(false);
        try {// 形も日付も正しい文字列のとき
            dateFormat.parse(str);
            System.out.println("2022/06/16(木曜日)  :OK");
        } catch (ParseException e) {
            System.out.println("2022/06/16(木曜日)  :NG");
        }

        try {// 形が間違っている文字列のとき
            dateFormat.parse(str1);
            System.out.println("2022/06/16()        :OK");
        } catch (ParseException e) {
            System.out.println("2022/06/16()        :NG");
        }

        try {// 存在しない日付が文字列のとき
            dateFormat.parse(str2);
            System.out.println("2022/06/31(金曜日)  :OK");
        } catch (ParseException e) {
            System.out.println("2022/06/31(金曜日)  :NG");
        }
        /*-------------------------------------*/
    }

}

出力:

setLenientがtrue(通常)のとき
2022/06/16(木曜日)  :OK
2022/06/16()        :NG
2022/06/31(金曜日)  :OK
setLenientがfalseのとき
2022/06/16(木曜日)  :OK
2022/06/16()        :NG
2022/06/31(金曜日)  :NG

setLenientがtrue、つまり通常の状態では、形が間違っているときだけNGになっています。一方で、setLenientをfalseにした場合には、「6/31」という存在しない日付を指定してもNGが出力されています。


もし自分の指定した日付文字列が日付的に正しいかどうか判断したい場合には、setLenientメソッドでfalseを指定し、チェックを行いましょう。



5.日付を西暦・和暦に変換する方法


日付を和暦に変換するには、ロケールのバリアントを”JP”に指定する必要があります。


日本のJava環境ならば、デフォルトのロケールは「ja_JP(言語:日本語、国:日本)」となっており、バリアントは設定されていません。このロケールを「ja_JP_JP(言語:日本語、国:日本、バリアント:日本)」にすることで、日本のカレンダーが使用され、和暦が使えるようになります。


ロケールを「ja_JP_JP」にするには、ロケール生成時に以下のように記述します。

Locale("ja", "JP", "JP")

言語、国、バリアントの順番に指定してください。


それでは実際にロケールを生成し、和暦に変換してみましょう。

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class JapaneseDate {
    public static void main(String[] args) {
        Locale defaultLocale = Locale.getDefault(); // デフォルトのロケールを取得
        Locale locale = new Locale("ja", "JP", "JP"); // バリアントを"JP"に指定してロケールを生成

        Date now = new Date(); // Dateのインスタンス"now"を生成

        SimpleDateFormat dateFormat1 = new SimpleDateFormat("GGGGyyyy年MM月dd日"); // パターンのみを指定し、SimpleDateFormatのインスタンス"dateFormat1"を生成
        SimpleDateFormat dateFormat2 = new SimpleDateFormat("GGGGy年MM月dd日", locale); // パターン、ロケールを指定し、SimpleDateFormatのインスタンス"dateFormat2"を生成

        String formatted = dateFormat1.format(now); // formatメソッドでフォーマット
        String JapaneseDate = dateFormat2.format(now); // formatメソッドでフォーマット

        System.out.println("デフォルトのロケール    :" + defaultLocale); // デフォルトのロケールを出力
        System.out.println("新たに生成したロケール  :" + locale); // 新しく生成したロケールを出力
        System.out.println("西暦    :" + formatted); // ロケールを設定しないでフォーマットした日付を出力
        System.out.println("和暦    :" + JapaneseDate); // 新しいロケールでフォーマットした日付を出力
    }
}

出力:

デフォルトのロケール    :ja_JP
新たに生成したロケール  :ja_JP_JP_#u-ca-japanese
西暦    :西暦2022年03月04日
和暦    :令和4年03月14日

デフォルトのロケールと、バリアントを指定し生成し直したロケールをそれぞれ出力してみました。上で解説したとおり、デフォルトではバリアントの設定がないのがわかります。


ロケールを使うのは、SimpleDateFormatのインスタンス生成のときです。パターン文字列に加えてロケールも指定してインスタンス生成をします。


つまり、和暦で日付を表示したいときには「ja_JP_JP」のロケールを指定し、西暦で日付を表示したいときには何も指定しなければよいということです。formatメソッドの使い方などは変わりません。



6.日付をフォーマットする際の注意点


ここまでは日付をフォーマットする方法を解説してきましたが、ここでは注意点を紹介します。

①    日時パターン文字列は大文字・小文字が区別される

SimpleDateFormatのインスタンス生成時に指定する日時パターン文字列は、大文字・小文字が区別されることに注意しましょう。


例えば、Hとhは同じ時間を表す文字ですが、Hは「一日における時(0 – 23)」、hは「午前/午後の時(1 – 12)」を表します。


ほかにも、Wは「月における週」で、wは「年における週」。Sは「ミリ秒」、sは「秒」など、大文字と小文字で違う表現になる文字列が多くあります。


その中でも特に注意が必要なのが、Mとmの違いです。Mは「年における月(状況依存)」を表しますが、mでは「分」を表すことになります。月も分もよく使う表現なので、これらの違いは覚えておくとよいでしょう。

②    SimpleDateFormatはスレッドセーフではない

もうひとつ注意するべき点として、SimpleDateFormatがスレッドセーフではないことが挙げられます。


スレッドセーフとは、スレッドを複数使用し並列で処理を行っても問題がない、ということです。クラスがスレッドセーフではないときには、同時に行う処理同士が影響を及ぼしあって想定と違う結果が得られることがあります。



この問題の解決方法をふたつ紹介します。


ひとつめは、スレッドごとに別々にSimpleDateFormatのインスタンスを生成する方法です。


スレッドセーフではないという問題は、同じインスタンスを複数のスレッドで使うことで起こってしまいます。このため、そもそもインスタンスの共有を行わなければ解決できます。


ふたつめは、日付のフォーマットにSimpleDateFormatではなく、DateTimeFormatterを使用する方法です。DateTimeFormatterはスレッドセーフなクラスであり、マルチスレッドでも問題なく使用できます。


インスタンスの生成方法、フォーマットの方法などが違うので、使う際には気を付けてください。


この記事をシェア