javadatejava-timedatetimeformatterjava-16

Is there any pattern to format and parse periods in a day, such as 'in the morning', 'in the afternoon' or 'at night'?


I want to express periods in the day, such as in the morning, in the afternoon, or at night, not just AM or PM.

Is there any pattern in java.time API to format and parse periods in a day, such as in the morning, in the afternoon, or at night using DateTimeFormatter e.g.

final DateTimeFormatter FORMATTER = DateTimeFormatter
                                        .ofPattern("<<pattern>>", Locale.ENGLISH);

// Expected output: in the morning
System.out.println(LocalTime.of(8, 20, 30).format(FORMATTER)); 

// Expected output: in the evening
System.out.println(LocalTime.of(20, 20, 30).format(FORMATTER));

Solution

  • Java 16 introduced a new formatter pattern symbol B and supporting methods in the DateTimeFormatter and DateTimeFormatterBuilder classes.

    Here are the strings that you can parse or generate using this symbol, in English for United States:

    Let’s see which hour falls into which of the six categories, using a pattern of "HH:mm B".

    IntStream
            .rangeClosed ( 0 , 23 )                  // Generate a stream of integers 0 through 23. 
            .mapToObj ( LocalTime.MIN :: withHour )  // Returns a `LocalTime` object. Start with the time 00:00, then switch out the hour.
            .map ( localTime -> localTime.format ( DateTimeFormatter.ofPattern ( "HH:mm B" ).withLocale ( Locale.of ( "en" , "US" ) ) ) )    // Generate text representing the value of each `LocalTime` object.
            .forEach ( System.out :: println );      // Dump to console.
    
    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
    

    Note: Do not forget to specify the applicable Locale because such texts are Locale-sensitive. Check Always specify a Locale with a date-time formatter for custom formats to learn more about the importance of specifying Locale while using a date-time formatting type.

    Switch that Locale to French language with Canada cultural norms (Locale.of( "fr" , "CA" )).

    00:00 minuit
    01:00 du mat.
    …
    11:00 du mat.
    12:00 midi
    13:00 après-midi
    …
    17:00 après-midi
    18:00 du soir
    …
    23:00 du soir
    

    More example code:

    Demo:

    import java.time.LocalDateTime;
    import java.time.LocalTime;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.Locale;
    
    class Main {
        private static final DateTimeFormatter FORMATTER = DateTimeFormatter
                .ofPattern("B", Locale.ENGLISH);
    
        public static void main(String[] args) {
            // Now in the default time zone
            ZonedDateTime now = ZonedDateTime.now();
            System.out.println(now);
            System.out.println(now.format(FORMATTER));
    
            // Now in America/New_York
            ZonedDateTime nowInNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
            System.out.println(nowInNy);
            System.out.println(nowInNy.format(FORMATTER));
    
            // A fixed time in the evening
            System.out.println(LocalTime.of(20, 20, 30).format(FORMATTER));
    
            // A fixed time at night
            System.out.println(LocalTime.of(23, 20, 30).format(FORMATTER));
    
            // Parsing a date-time with period specified as 'in the afternoon'
            String strDateTime = "22 Dec 2024 12:35:40 in the afternoon";
            LocalDateTime ldt = LocalDateTime.parse(strDateTime,
                    DateTimeFormatter.ofPattern("dd MMM uuuu hh:mm:ss B", Locale.ENGLISH));
            System.out.println(ldt);
        }
    }
    

    A sample output when executed in the afternoon on a JVM set with Europe/London time zone:

    2024-12-22T12:29:52.190717500Z[Europe/London]
    in the afternoon
    2024-12-22T07:29:52.220715700-05:00[America/New_York]
    in the morning
    in the evening
    at night
    2024-12-22T12:35:40
    

    Some examples of parsing/formatting with non-English Locales:

    import java.time.LocalTime;
    import java.time.format.DateTimeFormatter;
    import java.util.Locale;
    
    import static java.lang.System.out;
    
    class Main {
      private static final DateTimeFormatter FORMATTER =
              DateTimeFormatter.ofPattern("hh B");
    
      public static void main(String[] args) {
        // Examples of formatting a time in some non-English languages
    
        // A time at night
        LocalTime time = LocalTime.of(23, 20, 30);
    
        // Some non-English locales
        Locale localeFr = Locale.forLanguageTag("fr"); // French
        Locale localeEs = Locale.forLanguageTag("es"); // Spanish
        Locale localeDe = Locale.forLanguageTag("de"); // German
        Locale localeHi = Locale.forLanguageTag("hi"); // Hindi
        Locale localeBn = Locale.forLanguageTag("bn"); // Bangla
    
        out.println(time.format(FORMATTER.localizedBy(localeFr))); // French
        out.println(time.format(FORMATTER.localizedBy(localeEs))); // Spanish
        out.println(time.format(FORMATTER.localizedBy(localeDe))); // German
        out.println(time.format(FORMATTER.localizedBy(localeHi))); // Hindi
        out.println(time.format(FORMATTER.localizedBy(localeBn))); // Bangla
    
        // Examples of parsing date-time strings with period of the day
        // specified in a non-English language
        out.println(
                LocalTime.parse("11h du soir", // French
                        DateTimeFormatter.ofPattern("hh'h' B")
                                .localizedBy(localeFr)));
    
        out.println(
                LocalTime.parse("11h35 du soir", // French
                        DateTimeFormatter.ofPattern("hh'h'mm B")
                                .localizedBy(localeFr)));
    
        out.println(LocalTime.parse("11h de la noche", // Spanish
                DateTimeFormatter.ofPattern("hh'h' B")
                        .localizedBy(localeEs)));
    
        out.println(LocalTime.parse("11 abends", // German
                FORMATTER.localizedBy(localeDe)));
    
        out.println(LocalTime.parse("11:35 रात", // Hindi
                DateTimeFormatter.ofPattern("hh:mm B")
                        .localizedBy(localeHi)));
    
        out.println(LocalTime.parse("১১ রাত্রিবেলায়", // Bangla
                FORMATTER.localizedBy(localeBn)));
      }
    }
    

    Output:

    11 du soir
    11 de la noche
    11 abends
    11 रात
    ১১ রাত্রিবেলায়
    23:00
    23:35
    23:00
    23:00
    23:35
    23:00