Відформатуйте дату, використовуючи новий API часу дати


118

Я грав з новим API часу, але при виконанні цього:

public class Test {         
    public static void main(String[] args){
        String dateFormatted = LocalDate.now()
                                        .format(DateTimeFormatter
                                              .ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println(dateFormatted);
    }
}

Він кидає:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
    at java.time.LocalDate.get0(LocalDate.java:680)
    at java.time.LocalDate.getLong(LocalDate.java:659)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2543)
    at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2182)
    at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1745)
    at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1719)
    at java.time.LocalDate.format(LocalDate.java:1685)
    at Test.main(Test.java:23)

Переглядаючи вихідний код класу LocalDate, я бачу:

  private int get0(TemporalField field) {
        switch ((ChronoField) field) {
            case DAY_OF_WEEK: return getDayOfWeek().getValue();
            case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
            case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
            case DAY_OF_MONTH: return day;
            case DAY_OF_YEAR: return getDayOfYear();
            case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead");
            case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
            case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
            case MONTH_OF_YEAR: return month;
            case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead");
            case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
            case YEAR: return year;
            case ERA: return (year >= 1 ? 1 : 0);
        }
        throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
    }

Як описано в документі:

Цей метод створить форматів на основі простого шаблону літер та символів, як описано в документації на клас.

І всі ці букви визначені .

То чому б DateTimeFormatter.ofPatternце не дозволяє нам використовувати деякі букви візерунка?

Відповіді:


219

LocalDateпредставляє лише дату, а не DateTime. Отже, "HH: mm: ss" не має сенсу при форматуванні a LocalDate. Використовуйте LocalDateTimeнатомість, припускаючи, що ви хочете представити і дату, і час.


3
Як я можу відповісти на цю відповідь і спростувати той факт, що є як LocalDate, так і LocalDateTime об’єкт ...
Xials

Я хотів би просто працювати з LocalTime, як ви виконуєте форматування, не java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfWeek
стикаючись з

Неважливо: це працюєDateTimeFormatter.ofPattern("HH:mm:ss")
Samuel Owino

36

Я хотів би додати наступні деталі до правильної відповіді @James_D:

Передумови: Більшість бібліотек дат і часу ( java.util.Calendarна Java, див. Також. Net-DateTime або Dateв JavaScript або DateTimeв Perl) базуються на концепції універсального універсального унікального тимчасового типу (німецькою мовою є поетичний вираз " eierlegende Wollmilchsau "). У цій конструкції не може бути непідтримуваного поля. Але ціна висока: багато проблем із часом не можуть бути адекватно вирішені таким негнучким підходом, оскільки важко неможливо знайти спільний знаменник для всіх видів тимчасових об’єктів.

JSR-310 обрав інший спосіб , а саме дозволити різні тимчасові типи, які складаються з типових наборів підтримуваних вбудованих полів. Природним наслідком є ​​те, що не кожне можливе поле підтримується кожним типом (а користувачі можуть навіть визначати власні спеціалізовані поля). Також можливо запросити програмно кожен об'єкт типу TemporalAccessorдля його конкретного набору підтримуваних полів. Бо LocalDateми знаходимо:

DAY_OF_WEEK 
ALIGNED_DAY_OF_WEEK_IN_MONTH 
ALIGNED_DAY_OF_WEEK_IN_YEAR 
DAY_OF_MONTH 
DAY_OF_YEAR 
EPOCH_DAY 
ALIGNED_WEEK_OF_MONTH 
ALIGNED_WEEK_OF_YEAR 
MONTH_OF_YEAR 
PROLEPTIC_MONTH 
YEAR_OF_ERA 
YEAR 
ERA 

Не існує поля HOUR_OF_DAY, яке б пояснювало проблему UnsupportedTemporalTypeException. І якщо ми подивимось на відображення JSR- 310 - відображення символьних малюнків у поля, ми побачимо, що символ H відображається на непідтримуваний HOUR_OF_DAY:

/** Map of letters to fields. */  
private static final Map<Character, TemporalField> FIELD_MAP = new HashMap<>();
static {
  FIELD_MAP.put('G', ChronoField.ERA);
  FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA);
  FIELD_MAP.put('u', ChronoField.YEAR);
  FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR);
  FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR);
  FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR);
  FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR);
  FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR);
  FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH);
  FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH);
  FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK);
  FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY);
  FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY);
  FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY);
  FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM);
  FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM);
  FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR);
  FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE);
  FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND);
  FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY);
  FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND);
  FIELD_MAP.put('N', ChronoField.NANO_OF_DAY);    
}

Це картографічне поле не означає, що поле підтримується конкретним типом. Розбір відбувається в кілька етапів. Зображення поля - лише перший крок. Другий крок - розбір на необроблений об'єкт типу TemporalAccessor. І, нарешті, розбираємо делегатів на цільовий тип (тут LocalDate:) і нехай він вирішує, чи приймає він усі значення поля в проаналізованому проміжному об'єкті.


4
en.wiktionary.org/wiki/eierlegende_Wollmilchsau (буквально "яйце-шерсть, що відкладає яйця") Пристрій "все в одному" або людина, яка має (або заявляє, що має) лише позитивні ознаки і яка може (або намагається) виконувати роботу декількох спеціалізованих інструментів. :-)
Тревор Робінсон

6

Правильний для мене клас був, ZonedDateTimeякий включає в себе і час, і часову зону.

LocalDateне має інформації про час, тому ви отримаєте UnsupportedTemporalTypeException: Unsupported field: HourOfDay.

Ви можете використовувати, LocalDateTimeале тоді у вас немає інформації про часову зону, тому якщо ви спробуєте отримати доступ до цього (навіть за допомогою одного із заздалегідь визначених форматів), ви отримаєте UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.