Отформатируйте дату с помощью нового API даты и времени

120

Я играл с новым 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же мы не можем использовать несколько шаблонных букв?

user2336315
источник

Ответы:

221

LocalDateпредставляет собой просто дату, а не DateTime. Таким образом, "ЧЧ: мм: сс" не имеет смысла при форматировании файла LocalDate. Используйте LocalDateTimeвместо этого, если вы хотите , чтобы представить как дату и время.

James_D
источник
3
Как я могу проголосовать за этот ответ и проголосовать против того факта, что существует как LocalDate, так и объект LocalDateTime ...
Xials
Я хотел бы просто поработать с LocalTime, как выполнить форматирование, не сталкиваясь с этим исключением,java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: DayOfWeek
Сэмюэл Оуино,
Неважно: это работаетDateTimeFormatter.ofPattern("HH:mm:ss")
Сэмюэл Оуино
36

К правильному ответу @James_D я хотел бы добавить следующие детали:

Справочная информация: Большинство библиотек даты и времени ( java.util.Calendarв Java, см. Также .Net-DateTime, Dateв JavaScript или DateTimePerl) основаны на концепции универсального универсального уникального временного типа (на немецком языке есть поэтическое выражение " 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.

isapir
источник