日期时间格式化程序月份模式字母“L”失败“独立”月份名称

2022-09-01 06:09:59

我注意到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");
  }
}

只有最后一次尝试将“通过”。根据文档应该能够解析出文本格式。还要注意大写“M”与小写“m”的细微差别。tryParse("26-May-2015","dd-MMM-yyyy");LLL

这真的很烦人,因为默认情况下我无法解析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.forLanguageTag("ru")

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

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

我的问题是:

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

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

发短信:文本样式是根据所使用的图案字母数确定的。少于4个图案字母将使用缩写形式。正好有4个图案字母将使用完整的形式。正好有5个图案字母将使用窄格式。图案字母“L”、“c”和“q”指定文本样式的独立形式

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

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

更新

我向 Oracle 提交了两份文件:

  • 请求修复LLL(长格式文本)问题的错误:JDK-8114833(原始预言机评论ID: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”作为 March 的独立名称。


答案 2

根据javadocs的说法:

图案字母“L”、“c”和“q”指定文本样式的独立形式。

但是,我找不到太多关于“独立”形式应该是什么的信息。在查看代码时,我看到使用“L”选择并根据该javadoc:TextStyle.SHORT_STANDALONE

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

但是,这似乎不是它的工作方式。即使有三个字母,我也可以从这段代码中获得数字输出:

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

编辑

经过进一步调查,似乎(据我所知)这些代码的“独立”版本适用于您想要加载自己的与区域设置无关的数据的情况,大概使用.因此,默认情况下没有为 加载任何条目。DateTimeFormatterBuilderDateTimeFormatterTextStyle.SHORT_STANDALONE