Я предлагаю:
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 и посмотреть, что они говорят, хотя я бы не был слишком оптимистичен.