LoginSignup
1
0

More than 1 year has passed since last update.

Java16で追加されたDateTimeFormatterクラスの書式設定"B"について

Posted at

はじめに

Java16でDateTimeFormatterクラスの書式設定に "B" (period-of-day)が追加されました。
以下のドキュメントには意味として period-of-day 、例が in the morning とあるだけでよくわかりません。

そこで、この書式設定 "B" について実機確認とソースから調べました。

実機確認

各時刻で書式設定 B を指定したときにどのように変換されるかを確認。

確認用ソース

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

 public class TestPreiodOfDay  {
   public static void main(String[] args) {
     String s1,s2 ;
     int i ;
     LocalTime  lt   ;
     DateTimeFormatter f = DateTimeFormatter.ofPattern("HH:mm");
     DateTimeFormatter fmt_period = DateTimeFormatter.ofPattern("B");

     for ( i = 0 ; i < 24 ; i++ ) {
       lt  =  LocalTime.of(i, 00);
       s1 = lt.format(f);
       s2 = lt.format(fmt_period);
       System.out.println(s1 + " = " + s2);
     }
   }
 }

実行結果

00:00 = midnight
01:00 = at night
02:00 = at night
03:00 = at night
04:00 = at night
05:00 = at night
06:00 = in the morning
07:00 = in the morning
08:00 = in the morning
09:00 = in the morning
10:00 = in the morning
11:00 = in the morning
12:00 = noon
13:00 = in the afternoon
14:00 = in the afternoon
15:00 = in the afternoon
16:00 = in the afternoon
17:00 = in the afternoon
18:00 = in the evening
19:00 = in the evening
20:00 = in the evening
21:00 = at night
22:00 = at night
23:00 = at night

OpenJDKのソースを確認するとこの時間帯とメッセージはハードコーディングされており、固定になっています。
ただ、ロケールによって時間帯やメッセージは変わります。

ロケールが日本語(ja_JP.UTF-8) の場合
System Locale: LANG=ja_JP.UTF-8

実行結果(ロケール ja_JP.UTF-8)

00:00 = 真夜中
01:00 = 夜中
02:00 = 夜中
03:00 = 夜中
04:00 = 朝
05:00 = 朝
06:00 = 朝
07:00 = 朝
08:00 = 朝
09:00 = 朝
10:00 = 朝
11:00 = 朝
12:00 = 正午
13:00 = 昼
14:00 = 昼
15:00 = 昼
16:00 = 夕方
17:00 = 夕方
18:00 = 夕方
19:00 = 夜
20:00 = 夜
21:00 = 夜
22:00 = 夜
23:00 = 夜中

英語では6時から朝(in the morning)なのに対し、日本語では4時から「朝」です。

JDKソース確認

ドキュメントには記載されていませんがソースを見ると "B" 以外に "BBBB" , "BBBBB" の書式も用意されています。

jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
https://github.com/openjdk/jdk/blob/ddcd851c43aa97477c7e406490c0c7c7d71ac629/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java

DateTimeFormatterBuilder.java
 .....
      *  Pattern  Count  Equivalent builder methods
      *  -------  -----  --------------------------
      *    B       1      appendDayPeriodText(TextStyle.SHORT)
      *    BBBB    4      appendDayPeriodText(TextStyle.FULL)
      *    BBBBB   5      appendDayPeriodText(TextStyle.NARROW)

 .....
     private void parsePattern(String pattern) {
        .......
                 } else if (cur == 'B') {
                     switch (count) {
                         case 1 -> appendDayPeriodText(TextStyle.SHORT);
                         case 4 -> appendDayPeriodText(TextStyle.FULL);
                         case 5 -> appendDayPeriodText(TextStyle.NARROW);
                         default -> throw new IllegalArgumentException("Wrong number of pattern letters: " + cur);

"BBBB" または "BBBBB" を指定するとメッセージの長さが変わるようですが、en_US ロケールの場合はほとんど変わらずです。

時刻範囲に対するtypeは以下で定義されています。
jdk/make/data/cldr/common/supplemental/dayPeriods.xml

dayPeriods.xml

        <dayPeriodRules locales="en">
            <dayPeriodRule type="midnight" at="00:00"/> <!-- midnight -->
            <dayPeriodRule type="noon" at="12:00"/> <!-- noon -->
            <dayPeriodRule type="morning1" from="06:00" before="12:00"/>    <!-- morning -->
            <dayPeriodRule type="afternoon1" from="12:00" before="18:00"/>  <!-- afternoon -->
            <dayPeriodRule type="evening1" from="18:00" before="21:00"/>    <!-- evening -->
            <dayPeriodRule type="night1" from="21:00" before="06:00"/>  <!-- night -->
        </dayPeriodRules>
 .........
        <dayPeriodRules locales="ja">
            <dayPeriodRule type="midnight" at="00:00"/> <!-- 真夜中 -->
            <dayPeriodRule type="noon" at="12:00"/> <!-- 正午 -->
            <dayPeriodRule type="morning1" from="04:00" before="12:00"/>    <!-- 朝 -->
            <dayPeriodRule type="afternoon1" from="12:00" before="16:00"/>  <!-- 昼 -->
            <dayPeriodRule type="evening1" from="16:00" before="19:00"/>    <!-- 夕方 -->
            <dayPeriodRule type="night1" from="19:00" before="23:00"/>  <!-- 夜 -->
            <dayPeriodRule type="night2" from="23:00" before="04:00"/>  <!-- 夜中 -->
        </dayPeriodRules>

type に対するメッセージは以下で定義されています。
jdk/make/data/cldr/common/main/en.xml

en.xml
                <dayPeriods>
                    <dayPeriodContext type="format">
                        <dayPeriodWidth type="abbreviated">
                            <dayPeriod type="midnight">midnight</dayPeriod>
                            <dayPeriod type="am">AM</dayPeriod>
                            <dayPeriod type="am" alt="variant">am</dayPeriod>
                            <dayPeriod type="noon">noon</dayPeriod>
                            <dayPeriod type="pm">PM</dayPeriod>
                            <dayPeriod type="pm" alt="variant">pm</dayPeriod>
                            <dayPeriod type="morning1">in the morning</dayPeriod>
                            <dayPeriod type="afternoon1">in the afternoon</dayPeriod>
                            <dayPeriod type="evening1">in the evening</dayPeriod>
                            <dayPeriod type="night1">at night</dayPeriod>

jdk/make/data/cldr/common/main/ja.xml

ja.xml
                <dayPeriods>
                    <dayPeriodContext type="format">
                        <dayPeriodWidth type="abbreviated">
                            <dayPeriod type="midnight">真夜中</dayPeriod>
                            <dayPeriod type="am">午前</dayPeriod>
                            <dayPeriod type="noon">正午</dayPeriod>
                            <dayPeriod type="pm">午後</dayPeriod>
                            <dayPeriod type="morning1"></dayPeriod>
                            <dayPeriod type="afternoon1"></dayPeriod>
                            <dayPeriod type="evening1">夕方</dayPeriod>
                            <dayPeriod type="night1"></dayPeriod>
                            <dayPeriod type="night2">夜中</dayPeriod>
 ...........

書式設定 Bに対応する主な処理は DayPeriodPrinterParser クラスの format() で行われています。

     static final class DayPeriodPrinterParser implements DateTimePrinterParser {
     .....

         public boolean format(DateTimePrintContext context, StringBuilder buf) {
             Long hod = context.getValue(HOUR_OF_DAY);
             if (hod == null) {
                 return false;
             }
             Long moh = context.getValue(MINUTE_OF_HOUR);
             long value = Math.floorMod(hod, 24) * 60 + (moh != null ? Math.floorMod(moh, 60) : 0);
             Locale locale = context.getLocale();
             LocaleStore store = findDayPeriodStore(locale);
             final long val = value;
             final var map = DayPeriod.getDayPeriodMap(locale);
             value = map.keySet().stream()
                     .filter(k -> k.includes(val))
                     .min(DayPeriod.DPCOMPARATOR)
                     .map(map::get)
                     .orElse(val / 720); // fall back to am/pm
             String text = store.getText(value, textStyle);
             buf.append(text);
             return true;
         }

確認環境

CentOS Linux release 7.8.2003 (Core)
openjdk version "16.0.2" 2021-07-20

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0