DateTimeFormatter 月份模式字母 "L" 失败
DateTimeFormatter month pattern letter "L" fails
我注意到 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
格式说明符不处理任何文本,对我来说似乎是数字...
但是,如果我将区域设置更改为 Locale.forLanguageTag("ru")
,我会得到以下输出:
28-5-2015
28-Май-2015
28-5-2015
28-мая-2015
一切都很有趣,你同意吗?
我的问题是:
- 我期望每个都应该起作用是否合理?
- 我们是否应该至少将其中一些作为错误提交?
- 我是否误解了
L
模式说明符的用法。
引用文档中我认为的部分 '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.
更新
我已经向 Oracle 提交了两次:
- 请求修复 LLL(长格式文本)问题:JDK-8114833(原始 oracle 评论 ID:JI-9021661)
- 请求改进小写月份解析问题:评论ID:0(这也是一个错误吗??)
根据 javadocs:
Pattern letters 'L', 'c', and 'q' specify the stand-alone form of the text styles.
但是,我找不到太多关于 "stand-alone" 形式应该是什么的信息。在查看代码时,我看到使用 'L' 选择 TextStyle.SHORT_STANDALONE
并根据该 javadoc:
Short text for stand-alone use, typically an abbreviation. For example, day-of-week Monday might output "Mon".
然而,这似乎不是它的工作方式。即使只有三个字母,我也会从这段代码中得到数字输出:
DateTimeFormatter pattern = DateTimeFormatter.ofPattern ("dd-LLL-yyyy");
System.out.println (pattern.format (LocalDate.now ()));
编辑
经过进一步调查,似乎(据我所知)这些代码的 "stand-alone" 版本适用于当您想要加载自己的独立于语言环境的数据时,大概使用 DateTimeFormatterBuilder
.因此,默认情况下 DateTimeFormatter
没有为 TextStyle.SHORT_STANDALONE
.
加载条目
“独立”月名
我认为 '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”作为三月的独立名称。
虽然其他答案提供了有关模式字母 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
}
(手头没有Oracle数据库,未测试,如有错字请见谅)
我注意到 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
格式说明符不处理任何文本,对我来说似乎是数字...
但是,如果我将区域设置更改为 Locale.forLanguageTag("ru")
,我会得到以下输出:
28-5-2015
28-Май-2015
28-5-2015
28-мая-2015
一切都很有趣,你同意吗?
我的问题是:
- 我期望每个都应该起作用是否合理?
- 我们是否应该至少将其中一些作为错误提交?
- 我是否误解了
L
模式说明符的用法。
引用文档中我认为的部分 '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.
更新
我已经向 Oracle 提交了两次:
- 请求修复 LLL(长格式文本)问题:JDK-8114833(原始 oracle 评论 ID:JI-9021661)
- 请求改进小写月份解析问题:评论ID:0(这也是一个错误吗??)
根据 javadocs:
Pattern letters 'L', 'c', and 'q' specify the stand-alone form of the text styles.
但是,我找不到太多关于 "stand-alone" 形式应该是什么的信息。在查看代码时,我看到使用 'L' 选择 TextStyle.SHORT_STANDALONE
并根据该 javadoc:
Short text for stand-alone use, typically an abbreviation. For example, day-of-week Monday might output "Mon".
然而,这似乎不是它的工作方式。即使只有三个字母,我也会从这段代码中得到数字输出:
DateTimeFormatter pattern = DateTimeFormatter.ofPattern ("dd-LLL-yyyy");
System.out.println (pattern.format (LocalDate.now ()));
编辑
经过进一步调查,似乎(据我所知)这些代码的 "stand-alone" 版本适用于当您想要加载自己的独立于语言环境的数据时,大概使用 DateTimeFormatterBuilder
.因此,默认情况下 DateTimeFormatter
没有为 TextStyle.SHORT_STANDALONE
.
“独立”月名
我认为 '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”作为三月的独立名称。
虽然其他答案提供了有关模式字母 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
}
(手头没有Oracle数据库,未测试,如有错字请见谅)