java DateTimeFormatter 月份模式字母“L”失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30518954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DateTimeFormatter month pattern letter "L" fails
提问by YoYo
I noticed that java.time.format.DateTimeFormatter
is not able to parse out as expected. See below:
我注意到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");
}
}
Only the last attempt with tryParse("26-May-2015","dd-MMM-yyyy");
will "Pass". As per the documentation LLL
should be able to parse out textual format. Also note the subtle difference of the uppercase 'M' vs lowercase 'm'.
只有最后一次尝试tryParse("26-May-2015","dd-MMM-yyyy");
才会“通过”。根据文档LLL
应该能够解析出文本格式。还要注意大写“M”与小写“m”的细微差别。
This is really annoying, as I cannot by default parse out strings formatted by default by Oracle DB
这真的很烦人,因为默认情况下我无法解析 Oracle DB 默认格式化的字符串
SELECT TO_DATE(SYSDATE,'DD-MON-YYYY') AS dt FROM DUAL;
Similarly, for following program:
同样,对于以下程序:
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");
}
}
I get below output:
我得到以下输出:
28-5-2015
28-5-2015
28-5-2015
28-May-2015
Clearly the L
Format specifier doesn't treat anything textual, seems numeric to me ...
显然L
格式说明符不处理任何文本,对我来说似乎是数字......
However, if I change the Locale to Locale.forLanguageTag("ru")
, I get the following output:
但是,如果我将 Locale 更改为 ,则会Locale.forLanguageTag("ru")
得到以下输出:
28-5-2015
28-Май-2015
28-5-2015
28-мая-2015
All really interesting, wouldn't you agree?
一切都很有趣,你不同意吗?
The questions I have are:
我的问题是:
- Is it reasonable for me to expect that each of the should work?
- Should we at least submit some of these as a bug?
- Do I misunderstand the usage of the
L
pattern specifier.
- 我期望每个都应该工作是否合理?
- 我们应该至少提交其中一些作为错误吗?
- 我是否误解了
L
模式说明符的用法。
Quoting a part from the documentation that I percieved as 'it matters':
引用我认为“重要”的文档中的一部分:
Text:The text style is determined based on the number of pattern letters used. Less than 4 pattern letters will use the short form. Exactly 4 pattern letters will use the full form. Exactly 5 pattern letters will use the narrow form. Pattern letters 'L', 'c', and 'q' specify the stand-alone form of the text styles.
Number:If the count of letters is one, then the value is output using the minimum number of digits and without padding. Otherwise, the count of digits is used as the width of the output field, with the value zero-padded as necessary. The following pattern letters have constraints on the count of letters. Only one letter of 'c' and 'F' can be specified. Up to two letters of 'd', 'H', 'h', 'K', 'k', 'm', and 's' can be specified. Up to three letters of 'D' can be specified.
Number/Text:If the count of pattern letters is 3 or greater, use the Text rules above. Otherwise use the Number rules above.
文字:文字样式根据使用的图案字母的数量确定。少于 4 个模式字母将使用简写形式。正好 4 个模式字母将使用完整形式。恰好 5 个模式字母将使用窄形式。模式字母“L”、“c”和“q”指定文本样式的独立形式。
数字:如果字母数为1,则使用最小位数输出该值,不填充。否则,将使用数字计数作为输出字段的宽度,并根据需要填充零值。以下模式字母对字母数有限制。只能指定一个字母 'c' 和 'F'。最多可以指定两个字母“d”、“H”、“h”、“K”、“k”、“m”和“s”。最多可以指定三个字母“D”。
数字/文本:如果模式字母的数量为 3 或更多,请使用上面的文本规则。否则使用上面的数字规则。
UPDATE
更新
I have made two submissions to Oracle:
我已经向 Oracle 提交了两份意见书:
- Request for Bugfix for the LLL (Long Form Text) issue: JDK-8114833(original oracle Review ID: JI-9021661)
- Request for enhancement for the lowercase month parsing issue: Review ID: 0 (is that also a bug??)
- 请求修复LLL(长格式文本)问题:JDK-8114833(原始 oracle 审核 ID:JI-9021661)
- 小写月份解析问题的增强请求:评论 ID:0(这也是一个错误吗??)
采纳答案by Misha
“stand-alone” month name
“独立”月份名称
I believe 'L' is meant for languages that use a different word for the month itself versus the way it is used in a date. For example:
我相信“L”是指那些使用不同单词来表示月份本身而不是日期中使用方式的语言。例如:
Locale russian = Locale.forLanguageTag("ru");
asList("MMMM", "LLLL").forEach(ptrn ->
System.out.println(ptrn + ": " + ofPattern(ptrn, russian).format(Month.MARCH))
);
Output:
输出:
MMMM: марта
LLLL: Март
There shouldn't be any reason to use 'L' instead of 'M' when parsing a date.
解析日期时,没有任何理由使用“L”而不是“M”。
I tried the following to see which locales support stand-alone month name formatting:
我尝试了以下操作以查看哪些语言环境支持独立的月份名称格式:
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);
The following languages get a locale-specific stand-alone month name from 'LLLL':
以下语言从“LLLL”获得特定于语言环境的独立月份名称:
Catalan, Chinese, Croatian, Czech, Finnish, Greek, Hungarian, Italian, Lithuanian, Norwegian, Polish, Romanian, Russian, Slovak, Turkish, Ukrainian
加泰罗尼亚语、中文、克罗地亚语、捷克语、芬兰语、希腊语、匈牙利语、意大利语、立陶宛语、挪威语、波兰语、罗马尼亚语、俄语、斯洛伐克语、土耳其语、乌克兰语
All other languages get "3" as a stand-alone name for March.
所有其他语言都将“3”作为三月的独立名称。
回答by neuronaut
According to the javadocs:
根据javadocs:
Pattern letters 'L', 'c', and 'q' specify the stand-alone form of the text styles.
模式字母“L”、“c”和“q”指定文本样式的独立形式。
However, I couldn't find much about what the "stand-alone" form is supposed to be. In looking at the code I see that using 'L' selects TextStyle.SHORT_STANDALONE
and according to that javadoc:
但是,我找不到关于“独立”形式应该是什么的太多信息。在查看代码时,我看到使用 'L' 选择TextStyle.SHORT_STANDALONE
并根据该 javadoc:
Short text for stand-alone use, typically an abbreviation. For example, day-of-week Monday might output "Mon".
单独使用的短文本,通常是缩写。例如,星期几可能会输出“Mon”。
However, that isn't how it seems to work. Even with three letters I get numerical output from this code:
然而,这似乎不是它的工作方式。即使有三个字母,我也能从这段代码中得到数字输出:
DateTimeFormatter pattern = DateTimeFormatter.ofPattern ("dd-LLL-yyyy");
System.out.println (pattern.format (LocalDate.now ()));
Edit
编辑
After further investigation it seems (as near as I can tell) that the "stand-alone" versions of these codes are for when you want to load your own locale-independent data, presumably using DateTimeFormatterBuilder
. As such, by default DateTimeFormatter
has no entries loaded for TextStyle.SHORT_STANDALONE
.
经过进一步调查,似乎(据我所知)这些代码的“独立”版本适用于当您想要加载自己的与区域设置无关的数据时,大概使用DateTimeFormatterBuilder
. 因此,默认情况下DateTimeFormatter
没有为 加载任何条目TextStyle.SHORT_STANDALONE
。
回答by Ole V.V.
While the other answers give excellent information on pattern letter L
and date parsing, I should like to add that you should really avoid the problem altogether. Don't get date (and time) as string from your database. Instead use an appropriate datetime object.
虽然其他答案提供了有关模式字母L
和日期解析的极好信息,但我想补充一点,您真的应该完全避免这个问题。不要从数据库中获取日期(和时间)作为字符串。而是使用适当的日期时间对象。
String sql = "select sysdate as dt from dual;"
PreparedStatement stmt = yourDatabaseConnection.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
LocalDateTime dateTime = rs.getObject("dt", LocalDateTime.class);
// do something with dateTime
}
(Not tested since I haven't got an Oracle database at hand. Please forgive any typo.)
(未测试,因为我手头没有 Oracle 数据库。请原谅任何错字。)