Androidの日付フォーマット
日付型から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をそのまま使うのはやめましょう
- テストを書いて必要なフォーマットになっていることを確認しましょう
-
getBestDateTimePatternを使わず、withLocaleでJAPANESEを指定した場合 ↩︎
Discussion