⏱️

Androidの日付フォーマット

2022/07/10に公開

日付型からString型にフォーマットしたい時や、逆にString型から日付型に変換したいときは多い。ofPatternをそのまま使いうのは、間違えたり多言語対応が難しくなりがちなので注意が必要です。標準にある機能を使う方法を紹介します。

日付型に戻せるフォーマット

基本的には、ISO8601に合わせたフォーマットを行なって、どの言語でどの地域にいても同じフォーマットがされるようにします。

ISO8601を使う

DateTimeFormatter.ISO_INSTANTなどのDateTimeFormatterの定数になっているインスタンスを用います。

val s = "2022-07-09T08:05:23.653Z"
val date = ZonedDateTime.parse(s)

assertEquals(date.format(DateTimeFormatter.BASIC_ISO_DATE), "20220709Z")
assertEquals(date.format(DateTimeFormatter.ISO_DATE), "2022-07-09Z")
assertEquals(date.format(DateTimeFormatter.ISO_DATE_TIME), "2022-07-09T08:05:23.653Z")
assertEquals(date.format(DateTimeFormatter.ISO_INSTANT), "2022-07-09T08:05:23.653Z")
assertEquals(date.format(DateTimeFormatter.ISO_LOCAL_DATE), "2022-07-09")
assertEquals(date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), "2022-07-09T08:05:23.653")
assertEquals(date.format(DateTimeFormatter.ISO_LOCAL_TIME), "08:05:23.653")
assertEquals(date.format(DateTimeFormatter.ISO_OFFSET_DATE), "2022-07-09Z")
assertEquals(date.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), "2022-07-09T08:05:23.653Z")
assertEquals(date.format(DateTimeFormatter.ISO_OFFSET_TIME), "08:05:23.653Z")
assertEquals(date.format(DateTimeFormatter.ISO_ORDINAL_DATE), "2022-190Z")
assertEquals(date.format(DateTimeFormatter.ISO_TIME), "08:05:23.653Z")
assertEquals(date.format(DateTimeFormatter.ISO_WEEK_DATE), "2022-W27-6Z")
assertEquals(date.format(DateTimeFormatter.ISO_ZONED_DATE_TIME), "2022-07-09T08:05:23.653Z")
assertEquals(date.format(DateTimeFormatter.RFC_1123_DATE_TIME), "Sat, 9 Jul 2022 08:05:23 GMT")

日付型に戻さないフォーマット

ユーザーに日付を表示する場合には、現在のLocaleに沿った行なった方が好ましい。
たとえば、日本語であれば「2022年7月9日」と表記するなら、イギリスでは「9 July 2022」、アメリカでは「July 9, 2022」と表記すべきです。年月日の表記だけでなく、順番も異なっている。
これらの表記をした場合は日付型に戻すことはできません。
可能な限り、この記事のより上ある方法を選んでください。

DateTimeFormatterのLocalizedを使う

フォーマットを行う場合はある程度のフォーマットのパターンをDateTimeFormatterのofLocalizedDateとofLocalizedTime, ofLocalizedDateTimeを使ってフォーマットできます。
下記に例示がありますがofLocalizedDateTime例示は、ofLocalizedDateとofLocalizedTimeの組み合わせなので省略します。

ofLocalizedDate

Locale FULL LONG MEDIUM SHORT
JAPANESE 2022年7月9日土曜日 2022年7月9日 2022/07/09 2022/07/09
UK Saturday, 9 July 2022 9 July 2022 9 Jul 2022 09/07/2022
US Saturday, July 9, 2022 July 9, 2022 Jul 9, 2022 7/9/22

ofLocalizedTime

Locale FULL LONG MEDIUM SHORT
JAPANESE 8時05分23秒 Z 8:05:23 Z 8:05:23 8:05
UK 08:05:23 Z 08:05:23 Z 08:05:23 08:05
US 8:05:23 AM Z 8:05:23 AM Z 8:05:23 AM 8:05 AM

DateFormat.getBestDateTimePatternを使う

getBestDateTimePatternは、LocaleとパターンのStringから各Localeにあった順番に並べ替えてカンマやスペースが挿入されたパターンを返します。
DateTimeFormatter.ofPatternにパターンを適用して、フォーマットを行います。

パターンになる文字列になることは、テストを書いて確認することをお勧めします。ただし、DateFormatはandroidTestでしかテストできないので注意が必要。

val s = "2022-07-09T08:05:23.653Z"
val date = ZonedDateTime.parse(s)
val locale = Locale.US

val pattern = DateFormat.getBestDateTimePattern(locale, "yMMMMdEEEE")
val string = date.format(DateTimeFormatter.ofPattern(pattern).withLocale(locale))
assertEquals(string, "Saturday, July 9, 2022")

フォーマットされるパターン

yやMなどのシンボルとその数によってフォーマットされるパターンが異なります。
https://developer.android.com/reference/java/time/format/DateTimeFormatter#patterns を参照してください。
組み合わせによって異なる結果になります。

主なシンボル

シンボル [1] JAPANESE US
y 2022 2022年 2022
yy 22 22年 22
yyy 2022 2022年 2022
yyyy 2022 2022年 2022
yyyyy 02022 02022年 02022
M 7 7月 7
MM 07 07月 07
MMM 7月 7月 Jul
MMMM 7月 7月 July
MMMMM 7 7月 J
d 9 9日 9
dd 09 09日 09
h 8 午前8時 8 AM
hh 08 午前8時 8 AM
m 5 5 5
mm 05 5 5
s 23 23 23
ss 23 23 23
E Sat
EE Sat
EEE Sat
EEEE 土曜日 土曜日 Saturday
EEEEE S

まとめ

  • ofPatternをそのまま使うのはやめましょう
  • テストを書いて必要なフォーマットになっていることを確認しましょう
脚注
  1. getBestDateTimePatternを使わず、withLocaleでJAPANESEを指定した場合 ↩︎

Discussion