Подтвердить что ты не робот

Буквенное письмо месяца "DateTimeFormatter"

Я заметил, что java.time.format.DateTimeFormatter не может разобрать, как ожидалось. Увидеть ниже:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Play {
  public static void tryParse(String d,String f) {
    try { 
      LocalDate.parse(d, DateTimeFormatter.ofPattern(f)); 
      System.out.println("Pass");
    } catch (Exception x) {System.out.println("Fail");}
  }
  public static void main(String[] args) {
    tryParse("26-may-2015","dd-L-yyyy");
    tryParse("26-May-2015","dd-L-yyyy");
    tryParse("26-may-2015","dd-LLL-yyyy");
    tryParse("26-May-2015","dd-LLL-yyyy");
    tryParse("26-may-2015","dd-M-yyyy");
    tryParse("26-May-2015","dd-M-yyyy");
    tryParse("26-may-2015","dd-MMM-yyyy");
    tryParse("26-May-2015","dd-MMM-yyyy");
  }
}

Только последняя попытка с tryParse("26-May-2015","dd-MMM-yyyy"); пройдет". Согласно документации, LLL должен уметь анализировать текстовый формат. Также обратите внимание на небольшую разницу между прописными буквами "M" и строчными буквами "m".

Это действительно раздражает, так как я не могу по умолчанию разобрать строки, отформатированные по умолчанию в Oracle DB

SELECT TO_DATE(SYSDATE,'DD-MON-YYYY') AS dt FROM DUAL;

Аналогично для следующей программы:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Play {
  public static void output(String f) {
    LocalDate d = LocalDate.now();
    Locale l = Locale.US;
    // Locale l = Locale.forLanguageTag("ru");
    System.out.println(d.format(DateTimeFormatter.ofPattern(f,l)));
  }
  public static void main(String[] args) {
    output("dd-L-yyyy");
    output("dd-LLL-yyyy");
    output("dd-M-yyyy");
    output("dd-MMM-yyyy");
  }
}

Я получаю ниже вывод:

28-5-2015
28-5-2015
28-5-2015
28-May-2015

Очевидно, что спецификатор L Format не обрабатывает ничего текстового, мне кажется, числовым...

Однако, если я изменю Locale на Locale.forLanguageTag("ru"), я получу следующий вывод:

28-5-2015
28-Май-2015
28-5-2015
28-мая-2015

Все действительно интересно, ты не согласен?

У меня есть следующие вопросы:

  • Разумно ли мне ожидать, что каждый из них должен работать?
  • Должны ли мы хотя бы представить некоторые из них как ошибку?
  • Я неправильно понимаю использование спецификатора шаблона L

Цитирую часть из документации, которую я воспринял как "это важно":

Текст: стиль текста определяется на основе количества использованных букв шаблона. Менее 4 шаблонных букв будут использовать краткую форму. Точно 4 буквы шаблона будут использовать полную форму. Ровно 5 шаблонных букв будут использовать узкую форму. Шаблонные буквы "L", "c" и "q" определяют автономную форму стилей текста.

Число: если количество букв равно единице, то значение выводится с использованием минимального количества цифр и без дополнения. В противном случае в качестве ширины поля вывода используется количество цифр, при необходимости значение заполняется нулями. Следующие буквы шаблона имеют ограничения на количество букв. Можно указать только одну букву "с" и "F". Можно указать до двух букв "d", "H", "h", "K", "k", "m" и "s". Можно указать до трех букв "D".

Число/текст: если количество букв шаблона составляет 3 или более, используйте текстовые правила выше. В противном случае используйте приведенные выше правила нумерации.

ОБНОВИТЬ

Я сделал два представления в Oracle:

  • Запрос исправления для проблемы с LLL (длинный текст): JDK-8114833 (оригинальный идентификатор обзора оракула: JI-9021661)
  • Запрос на исправление проблемы разбора нижнего регистра: ID обзора: 0 (это тоже ошибка??)
4b9b3361

Ответ 1

"автономное" название месяца

Я считаю, что "L" предназначен для языков, которые используют другое слово для самого месяца в сравнении с тем, как оно используется в дате. Например:

Locale russian = Locale.forLanguageTag("ru");

asList("MMMM", "LLLL").forEach(ptrn -> 
    System.out.println(ptrn + ": " + ofPattern(ptrn, russian).format(Month.MARCH))
);

Выход:

MMMM: марта
LLLL: Март

При анализе даты не должно быть никаких причин использовать "L" вместо "M".

Я попробовал следующее: какие локали поддерживают автономное форматирование имени месяца:

Arrays.stream(Locale.getAvailableLocales())
    .collect(partitioningBy(
                loc -> "3".equals(Month.MARCH.getDisplayName(FULL_STANDALONE, loc)),
                mapping(Locale::getDisplayLanguage, toCollection(TreeSet::new))
    )).entrySet().forEach(System.out::println);

Следующие языки получают автономное имя месяца с локальным именем из "LLLL":

Каталанский, китайский, хорватский, чешский, финский, греческий, венгерский, итальянский, литовский, норвежский, польский, румынский, русский, словацкий, турецкий, украинский

Все остальные языки получают "3" в качестве автономного имени для марта.

Ответ 2

В соответствии с javadocs:

Буквы шаблонов "L", "c" и "q" указывают автономную форму стилей текста.

Однако я не мог много узнать о том, что такое "автономная" форма. Смотря на код, я вижу, что использование "L" выбирает TextStyle.SHORT_STANDALONE и в соответствии с этим javadoc:

Краткий текст для автономного использования, обычно аббревиатура. Например, день недели в понедельник может выводить "Mon".

Однако это не так, как кажется. Даже с тремя буквами я получаю числовой вывод из этого кода:

DateTimeFormatter pattern = DateTimeFormatter.ofPattern ("dd-LLL-yyyy");
System.out.println (pattern.format (LocalDate.now ()));

Edit

После дальнейшего исследования кажется (насколько я могу судить), что "автономные" версии этих кодов предназначены для того, чтобы вы загружали свои независимые от языка данные, предположительно используя DateTimeFormatterBuilder. Таким образом, по умолчанию DateTimeFormatter не имеет загруженных записей для TextStyle.SHORT_STANDALONE.