Синтаксические и форматирование LocalDate ненужного времени и часовой пояс

Darnoj:

Редактировать :

Я открыл ошибку , и это было подтверждено Oracle. Вы можете следить за разрешением здесь: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8216414


Я взаимодействия с хранилищем LDAP который хранит дату рождения человека, с указанием времени и часового пояса, как это:

  • Если дата рождения является «27-12-2018», то строка LDAP является «20181227000000 + 0000».

Я не могу найти способ для синтаксического анализа и форматирования даты рождения , используя один и тот же шаблон .

Следующий код работает хорошо для форматирования, но не для разбора:

LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMdd'000000+0000'";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);

// Outputs correctly 20181227000000+0000
date.format(birthdateFormat);

// Throw a DatetimeParseException at index 0
date = LocalDate.parse("20181227000000+0000", birthdateFormat);

А следующий код работает хорошо для синтаксического анализа, но не для форматирования

LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMddkkmmssxx";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);

// Throws a UnsupportedTemporalTypeException for ClockHourOfDay not supported
// Anyway I would have an unwanted string with non zero hour, minute, second, timezone
date.format(birthdateFormat);

// Parse correctly the date to 27-12-2018
date = LocalDate.parse("20181227000000+0000", birthdateFormat);

Какой шаблон может удовлетворить и синтаксический анализ и форматирование?

Могу ли я вынужден использовать 2 различных моделей?

Я спрашиваю потому, что шаблон настроен в файле свойств. Я хочу настроить 1 шаблон только в этом файле свойств. Я хотел бы экстернализацию шаблона, поскольку LDAP не является частью моего проекта, это общий ресурс и у меня нет гарантии, что формат не может измениться.

Ole VV:

Я предлагаю:

    LocalDate date = LocalDate.of(2018, Month.DECEMBER, 27);
    String pattern = "yyyyMMddHHmmssxx";
    DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);

    // Outputs 20181227000000+0000
    String formatted = date.atStartOfDay(ZoneOffset.UTC).format(birthdateFormat);
    System.out.println(formatted);

    // Parses to 2018-12-27T00:00Z
    OffsetDateTime odt = OffsetDateTime.parse("20181227000000+0000", birthdateFormat);
    System.out.println(odt);
    // Validate
    if (! odt.toLocalTime().equals(LocalTime.MIN)) {
        System.out.println("Unexpected time of day: " + odt);
    }
    if (! odt.getOffset().equals(ZoneOffset.UTC)) {
        System.out.println("Unexpected time zone offset: " + odt);
    }
    // Converts to 2018-12-27
    date = odt.toLocalDate();
    System.out.println(date);

Строка LDAP представляет собой как дату, время и UTC смещение. Хорошее решение заключается в том , что уважать и создавать все те , при форматировании (время суток настройки до 00:00 и смещение 0) и разбор их всех обратно (в лучшем случае также проверки их улова в случае возникновения каких - либо сюрпризов). Преобразование между LocalDateи OffsetDateTimeпросто , когда вы знаете , как.

Редактирование 3: Разрешение шаблона должны быть настроено

... шаблон настраивается в файле свойств ... Я хочу, чтобы настроить 1 шаблон только в этом файле свойств.

... У меня нет никакой гарантии, что формат не может измениться.

Для того, чтобы принять во внимание возможность, что картина однажды может не содержать время суток и / или нет UTC компенсировали использовать этот форматировщик в приведенном выше коде:

    DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
            .appendPattern(pattern)
            .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
            .toFormatter()
            .withZone(ZoneOffset.UTC);

Это определяет время по умолчанию день (в полночь) и по умолчанию смещения (0). До тех пор, как время и смещение определяется в строке с LDAP, по умолчанию не используются.

Если вы думаете, что становится слишком сложным, с использованием двух настроенных форматов, один для форматирования и один для разбора, может быть лучшим решением (наименее раздражающий раствор) для вас.

Изменить: Как избежать преобразования типов

Я считаю , что выше хорошее решение. Однако, если вы настаиваете расторгающий переход от LocalDateв ZonedDateTimeиспользовании atStartOfDayи с OffsetDateTimeпомощью toLocalDate, что можно с помощью следующей хака:

    DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4, 4, SignStyle.NEVER)
            .appendValue(ChronoField.MONTH_OF_YEAR, 2, 2, SignStyle.NEVER)
            .appendValue(ChronoField.DAY_OF_MONTH, 2, 2, SignStyle.NEVER)
            .appendLiteral("000000+0000")
            .toFormatter();

    // Outputs 20181227000000+0000
    String formatted = date.format(birthdateFormat);
    System.out.println(formatted);

    // Parses into 2018-12-27
    date = LocalDate.parse("20181227000000+0000", birthdateFormat);
    System.out.println(date);

Я указав точную ширину каждого поля так, что верстальщик может знать, где, чтобы отделить их в строке при разборе.

Изменить 2: Является ли это ошибка в анализе?

Я бы сразу ожидал yyyyMMdd'000000+0000'работать как для форматирования и разбора. Вы можете попробовать подав ошибка с Oracle и видя , что они говорят, хотя я бы не пчелы слишком оптимистично.

рекомендация

отhttp://43.154.161.224:23101/article/api/json?id=204778&siteId=1