如何将 DateTimeFormatter 用于模式 dMMyyyy
How to use DateTimeFormatter for pattern dMMyyyy
我需要使用 DateTimeFormatter 将字符串解析为 LocalDate。
有 2 种不同的情况,模式字符串 dMMyy 或 ddMMyy (20320, 020320, 120320) 和模式字符串 ddMMyyyy 或 dMMyyyy (2032020, 02032020, 12032020)。
对于第一种情况,我可以只使用 DateTimeFormatter.ofPattern("dMMyy"),它适用于 5 或 6 位长日期。
@Test
public void dateConversionyy() {
DateTimeFormatter worksShortd = DateTimeFormatter.ofPattern("dMMyy");
DateTimeFormatter worksShortdd = DateTimeFormatter.ofPattern("ddMMyy");
String longString = "120320";
String leadingZeroString = "020320";
String shortString = "20320";
LocalDate res = LocalDate.parse(longString, worksShortd);
assertNotNull(res);
LocalDate res2 = LocalDate.parse(longString, worksShortdd);
assertNotNull(res2);
assertEquals(res, res2);
LocalDate res3 = LocalDate.parse(shortString, worksShortd);
assertNotNull(res3);
LocalDate res4 = LocalDate.parse(leadingZeroString, worksShortd);
assertNotNull(res4);
assertEquals(res3, res4);
LocalDate res5 = LocalDate.parse(leadingZeroString, worksShortdd);
assertNotNull(res);
assertEquals(res3, res5);
}
对于第二种情况,我认为我可以使用模式“dMMyyyy”,但它只是不解析任何输入字符串。
@Test
public void dateConversionyyyy() {
LocalDate res;
DateTimeFormatter failsLong = DateTimeFormatter.ofPattern("dMMyyyy");
DateTimeFormatter worksLong = DateTimeFormatter.ofPattern("ddMMyyyy");
String longString = "13082020";
String shortString = "3082020";
boolean notParsed1 = false;
try {
LocalDate.parse(longString, failsLong);
} catch (DateTimeParseException e) {
notParsed1 = true;
}
assertTrue(notParsed1);
res = LocalDate.parse(longString, worksLong);
assertNotNull(res);
boolean notParsed2 = false;
try {
LocalDate.parse(shortString, failsLong);
} catch (DateTimeParseException e) {
notParsed2 = true;
}
assertTrue(notParsed2);
}
编辑:
我的问题:有没有办法实例化 DateTimeFormatter use DateTimeFormatter.ofPattern 以解析 7-8 位数字变体的方式?
编辑问题使@user16320675 的答案匹配,因为它解决了我的问题。
DateTimeFormatterBuilder.appendValue(TemporalField, int)
我正在使用并稍微修改 user16320675 在评论中提到的想法:
try using a DateTimeFormatterBuilder
and use
appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER)
, use a
fixed size for the other fields.
DateTimeFormatter worksLong = new DateTimeFormatterBuilder()
.appendPattern("dMM")
.appendValue(ChronoField.YEAR, 4)
.toFormatter(Locale.ROOT);
System.out.println(LocalDate.parse("2032020", worksLong));
System.out.println(LocalDate.parse("02032020", worksLong));
System.out.println(LocalDate.parse("12032020", worksLong));
输出:
2020-03-02
2020-03-02
2020-03-12
如果您希望在构建格式化程序时更加一致:
DateTimeFormatter worksLong = new DateTimeFormatterBuilder()
.appendValue(ChronoField.DAY_OF_MONTH)
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendValue(ChronoField.YEAR, 4)
.toFormatter(Locale.ROOT);
结果是一样的
为什么您的模式 dMMyyyy
不起作用?
年份,或更准确地说是模式字母 u
、y
和 Y
,在 DateTimeFormatter.ofPattern()
中是特殊的。对于其他数字字段,四个模式字母表示宽度恰好为 4 的字段。多年来,它意味着 最小字段宽度 为 4。这反过来会破坏 adjecent 值解析 在两位数年份的情况下有效。相反,我认为解析器会贪婪地使用所有 7 位或 8 位数字作为月份中的第几天,然后找不到它们之后的月份。
相邻值解析 是使您的模式dMMyy
起作用的原因。它基本上允许一系列字段中没有分隔符的 first(并且只有第一个)在所有其他字段具有固定宽度时具有可变宽度。所以我们让相邻值解析再次起作用的技巧是让年份字段的宽度固定为4。构建器的appendValue
方法可以做到这一点。
那么为什么 yy
有效而 yyyy
无效呢?因为岁月是特殊的。 yy
表示固定宽度为2。yyyy
表示最小宽度为4。
文档引用和链接
来自DateTimeFormatter
的文档:
Year: The count of letters determines the minimum field width below which padding is used. If the count of letters is two, then a
reduced two digit form is used. For printing, this outputs the
rightmost two digits. For parsing, this will parse using the base
value of 2000, resulting in a year within the range 2000 to 2099
inclusive. If the count of letters is less than four (but not two),
then the sign is only output for negative years as per
SignStyle.NORMAL
. Otherwise, the sign is output if the pad width is
exceeded, as per SignStyle.EXCEEDS_PAD
.
我需要使用 DateTimeFormatter 将字符串解析为 LocalDate。
有 2 种不同的情况,模式字符串 dMMyy 或 ddMMyy (20320, 020320, 120320) 和模式字符串 ddMMyyyy 或 dMMyyyy (2032020, 02032020, 12032020)。
对于第一种情况,我可以只使用 DateTimeFormatter.ofPattern("dMMyy"),它适用于 5 或 6 位长日期。
@Test
public void dateConversionyy() {
DateTimeFormatter worksShortd = DateTimeFormatter.ofPattern("dMMyy");
DateTimeFormatter worksShortdd = DateTimeFormatter.ofPattern("ddMMyy");
String longString = "120320";
String leadingZeroString = "020320";
String shortString = "20320";
LocalDate res = LocalDate.parse(longString, worksShortd);
assertNotNull(res);
LocalDate res2 = LocalDate.parse(longString, worksShortdd);
assertNotNull(res2);
assertEquals(res, res2);
LocalDate res3 = LocalDate.parse(shortString, worksShortd);
assertNotNull(res3);
LocalDate res4 = LocalDate.parse(leadingZeroString, worksShortd);
assertNotNull(res4);
assertEquals(res3, res4);
LocalDate res5 = LocalDate.parse(leadingZeroString, worksShortdd);
assertNotNull(res);
assertEquals(res3, res5);
}
对于第二种情况,我认为我可以使用模式“dMMyyyy”,但它只是不解析任何输入字符串。
@Test
public void dateConversionyyyy() {
LocalDate res;
DateTimeFormatter failsLong = DateTimeFormatter.ofPattern("dMMyyyy");
DateTimeFormatter worksLong = DateTimeFormatter.ofPattern("ddMMyyyy");
String longString = "13082020";
String shortString = "3082020";
boolean notParsed1 = false;
try {
LocalDate.parse(longString, failsLong);
} catch (DateTimeParseException e) {
notParsed1 = true;
}
assertTrue(notParsed1);
res = LocalDate.parse(longString, worksLong);
assertNotNull(res);
boolean notParsed2 = false;
try {
LocalDate.parse(shortString, failsLong);
} catch (DateTimeParseException e) {
notParsed2 = true;
}
assertTrue(notParsed2);
}
编辑:
我的问题:有没有办法实例化 DateTimeFormatter use DateTimeFormatter.ofPattern 以解析 7-8 位数字变体的方式?
编辑问题使@user16320675 的答案匹配,因为它解决了我的问题。
DateTimeFormatterBuilder.appendValue(TemporalField, int)
我正在使用并稍微修改 user16320675 在评论中提到的想法:
try using a
DateTimeFormatterBuilder
and useappendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER)
, use a fixed size for the other fields.
DateTimeFormatter worksLong = new DateTimeFormatterBuilder()
.appendPattern("dMM")
.appendValue(ChronoField.YEAR, 4)
.toFormatter(Locale.ROOT);
System.out.println(LocalDate.parse("2032020", worksLong));
System.out.println(LocalDate.parse("02032020", worksLong));
System.out.println(LocalDate.parse("12032020", worksLong));
输出:
2020-03-02 2020-03-02 2020-03-12
如果您希望在构建格式化程序时更加一致:
DateTimeFormatter worksLong = new DateTimeFormatterBuilder()
.appendValue(ChronoField.DAY_OF_MONTH)
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendValue(ChronoField.YEAR, 4)
.toFormatter(Locale.ROOT);
结果是一样的
为什么您的模式 dMMyyyy
不起作用?
年份,或更准确地说是模式字母 u
、y
和 Y
,在 DateTimeFormatter.ofPattern()
中是特殊的。对于其他数字字段,四个模式字母表示宽度恰好为 4 的字段。多年来,它意味着 最小字段宽度 为 4。这反过来会破坏 adjecent 值解析 在两位数年份的情况下有效。相反,我认为解析器会贪婪地使用所有 7 位或 8 位数字作为月份中的第几天,然后找不到它们之后的月份。
相邻值解析 是使您的模式dMMyy
起作用的原因。它基本上允许一系列字段中没有分隔符的 first(并且只有第一个)在所有其他字段具有固定宽度时具有可变宽度。所以我们让相邻值解析再次起作用的技巧是让年份字段的宽度固定为4。构建器的appendValue
方法可以做到这一点。
那么为什么 yy
有效而 yyyy
无效呢?因为岁月是特殊的。 yy
表示固定宽度为2。yyyy
表示最小宽度为4。
文档引用和链接
来自DateTimeFormatter
的文档:
Year: The count of letters determines the minimum field width below which padding is used. If the count of letters is two, then a reduced two digit form is used. For printing, this outputs the rightmost two digits. For parsing, this will parse using the base value of 2000, resulting in a year within the range 2000 to 2099 inclusive. If the count of letters is less than four (but not two), then the sign is only output for negative years as per
SignStyle.NORMAL
. Otherwise, the sign is output if the pad width is exceeded, as perSignStyle.EXCEEDS_PAD
.