DateTimeFormatter月模式字母“L”失败

我注意到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");的最后一次尝试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格式说明符不对待任何文本,对我来说似乎是数字…

但是,如果我将Locale更改为Locale.forLanguageTag("ru") ,我会得到以下输出:

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

一切都很有意思,你不同意吗?

我的问题是:

  • 我期望每一个应该有效吗?
  • 我们至少应该提交其中一些作为错误吗?
  • 我是否误解了L模式说明符的用法。

引用我认为“重要”的文档中的一部分:

文本:文本样式根据使用的模式字母数确定。 少于4个模式字母将使用简短forms。 正好4个模式字母将使用完整forms。 正好5个模式字母将使用窄格式。 模式字母’L’,’c’和’q’指定文本样式的独立forms

Number:如果字母数为1,则使用最小位数输出该值,不进行填充。 否则,将使用位数作为输出字段的宽度,并根据需要将值填充为零。 以下模式字母对字母数量有约束。 只能指定一个’c’和’F’字母。 最多可以指定两个字母“d”,“H”,“h”,“K”,“k”,“m”和“s”。 最多可以指定三个字母’D’。

数字/文本: 如果模式字母的数量为3或更大,请使用上面的文本规则 。 否则使用上面的数字规则。

UPDATE

我向Oracle提交了两份提交内容:

  • 请求LLL(长格式文本)问题的修正: JDK-8114833 (原始oracle评论ID:JI-9021661)
  • 请求增强小写月份解析问题:审核ID:0(这也是一个错误??)

“独立”月份名称

我相信’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”作为March的独立名称。

根据javadocs:

模式字母’L’,’c’和’q’指定文本样式的独立forms。

但是,我无法找到“独立”forms应该是什么。 在查看代码时,我看到使用’L’选择TextStyle.SHORT_STANDALONE并根据该javadoc:

独立使用的简短文本,通常是缩写。 例如,星期一星期一可能输出“星期一”。

然而,这似乎不是它的工作方式。 即使有三个字母,我也从这段代码得到数字输出:

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

编辑

经过进一步研究后,似乎(尽我所知)这些代码的“独立”版本适用于您希望加载自己的与语言环境无关的数据,大概是使用DateTimeFormatterBuilder 。 因此,默认情况下, DateTimeFormatter没有为TextStyle.SHORT_STANDALONE加载任何条目。