Буквенное письмо месяца "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 (это тоже ошибка??)
Ответы
Ответ 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
.