DateTimeFormatter 接受多个日期并转换为一个(java.time 库)
DateTimeFormatter Accepting Multiple Dates and Converting to One (java.time library)
我正在尝试编写一个 DateTimeFormatter
,它允许我采用多种不同的 String
格式,然后将 String
格式转换为特定类型。由于项目的范围和已经存在的代码,我不能使用不同类型的格式化程序。
例如,我想接受 MM/dd/yyyy
以及 yyyy-MM-dd'T'HH:mm:ss
但是当我打印时我只想打印成 MM/dd/yyyy
格式并在我调用时以格式LocalDate.format(formatter);
有人可以就如何使用 java.time.format.*;
提出建议吗
这是我在 org.joda
中的做法:
// MM/dd/yyyy format
DateTimeFormatter monthDayYear = DateTimeFormat.forPattern("MM/dd/yyyy");
// array of parsers, with all possible input patterns
DateTimeParser[] parsers = {
// parser for MM/dd/yyyy format
monthDayYear.getParser(),
// parser for yyyy-MM-dd'T'HH:mm:ss format
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss").getParser()
};
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// use the monthDayYear formatter for output (monthDayYear.getPrinter())
// and parsers array for input (parsers)
.append(monthDayYear.getPrinter(), parsers)
// create formatter (using UTC to avoid DST problems)
.toFormatter()
.withZone(DateTimeZone.UTC);
我还没有在网上找到 good/working 这个例子。
你问的不可能。
DateTimeFormatter
是一个 final
class,所以你不能子 class 它来实现你自己的行为。
构造函数是包私有的,所以不能自己调用。创建 DateTimeFormatter
的唯一方法是使用 DateTimeFormatterBuilder
。请注意,用于创建 DateTimeFormatter
的 static
辅助方法在内部使用 DateTimeFormatterBuilder
,例如
public static DateTimeFormatter ofPattern(String pattern) {
return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
}
DateTimeFormatterBuilder
也是一个 final
class,不能被子classed,并且它没有提供任何方法来提供多种替代格式以供使用,如你所愿。
总之,DateTimeFormatter
已关闭,无法扩展。如果您的代码只能使用 DateTimeFormatter
,那您就倒霉了。
正确,应该接受。
检查字符串的长度
作为替代方案,您可以简单地测试字符串的长度并应用两个格式化程序之一。
DateTimeFormatter fDateOnly = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
DateTimeFormatter fDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME ;
LocalDate ld = null ;
if( input.length() == 10 ) {
try {
ld = LocalDate.parse( input , fDateOnly ) ;
} catch (DateTimeParseException e ) {
…
}
} else if ( input.length() == 19 ) {
try {
LocalDateTime ldt = LocalDateTime.parse( input , fDateTime ) ;
ld = ldt.toLocalDate() ;
} catch (DateTimeParseException e ) {
…
}
} else {
// Received unexpected input.
…
}
String output = ld.format( fDateOnly ) ;
请注意,您可以让 java.time 在生成表示日期时间值的字符串时自动本地化,而不是硬编码特定格式。参见 DateTimeFormatter.ofLocalizedDate。
我已经用 JDK 1.8.0_131 测试了 Mac OS X 和 JDK 1.8.0111 用于 Windows(均有效)。
我创建了一个带有可选部分(由 []
分隔)的 DateTimeFormatter
,以解析这两种情况(MM/dd/yyyy
和 yyyy-MM-dd'T'HH:mm:ss
)。
相同的格式化程序适用于您的案例 (LocalDate
),但下面有一些注意事项。
// parse both formats (use optional section, delimited by [])
DateTimeFormatter parser = DateTimeFormatter.ofPattern("[MM/dd/yyyy][yyyy-MM-dd'T'HH:mm:ss]");
// parse MM/dd/yyyy
LocalDate d1 = LocalDate.parse("10/16/2016", parser);
// parse yyyy-MM-dd'T'HH:mm:ss
LocalDate d2 = LocalDate.parse("2016-10-16T10:20:30", parser);
// parser.format(d1) is the same as d1.format(parser)
System.out.println(parser.format(d1));
System.out.println(parser.format(d2));
输出为:
10/16/2016
10/16/2016
PS: 这仅适用于 LocalDate
。如果我尝试用时间字段格式化一个对象(比如 LocalDateTime
),两种格式都会被使用:
System.out.println(parser.format(LocalDateTime.now()));
这会打印:
06/18/20172017-06-18T07:40:55
请注意,它使用两种模式进行格式化。我的猜测是格式化程序检查对象是否在每个可选部分中都有字段。由于 LocalDate
没有时间字段 (hour/minute/second),第二个模式失败,它只打印第一个 (MM/dd/yyyy
)。但是LocalDateTime
有所有的时间字段,而且两种模式都是有效的,所以都用来格式化。
我的结论是:这不是一个通用的解决方案(如 Joda-Time 的版本),它更像是一个 "lucky" 案例,其中涉及的模式创建了所需的情况。但我不会在所有情况下都依赖它。
无论如何,如果你只是使用LocalDate
,你可以尝试使用这个代码。但是,如果您正在使用其他类型,那么您可能必须对输出使用 另一个 格式化程序,如下所示:
// parser/formatter for month/day/year
DateTimeFormatter mdy = DateTimeFormatter.ofPattern("MM/dd/yyyy");
// parser for both patterns
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// optional MM/dd/yyyy
.appendOptional(mdy)
// optional yyyy-MM-dd'T'HH:mm:ss (use built-in formatter)
.appendOptional(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// create formatter
.toFormatter();
// parse MM/dd/yyyy
LocalDate d1 = LocalDate.parse("10/16/2016", parser);
// parse yyyy-MM-dd'T'HH:mm:ss
LocalDate d2 = LocalDate.parse("2016-10-16T10:20:30", parser);
// use mdy to format
System.out.println(mdy.format(d1));
System.out.println(mdy.format(d2));
// format object with time fields: using mdy formatter to avoid multiple pattern problem
System.out.println(mdy.format(LocalDateTime.now()));
输出为:
10/16/2016
10/16/2016
06/18/2017
可以编写解析部分,并已添加到 ThreeTen-Extra library. The relevant code is here 中,为了清楚起见,将其包含在下面。关键技巧是使用 parseUnresolved()
找出正确的格式:
public static <T> T parseFirstMatching(CharSequence text, TemporalQuery<T> query, DateTimeFormatter... formatters) {
Objects.requireNonNull(text, "text");
Objects.requireNonNull(query, "query");
Objects.requireNonNull(formatters, "formatters");
if (formatters.length == 0) {
throw new DateTimeParseException("No formatters specified", text, 0);
}
if (formatters.length == 1) {
return formatters[0].parse(text, query);
}
for (DateTimeFormatter formatter : formatters) {
try {
ParsePosition pp = new ParsePosition(0);
formatter.parseUnresolved(text, pp);
int len = text.length();
if (pp.getErrorIndex() == -1 && pp.getIndex() == len) {
return formatter.parse(text, query);
}
} catch (RuntimeException ex) {
// should not happen, but ignore if it does
}
}
throw new DateTimeParseException("Text '" + text + "' could not be parsed", text, 0);
}
不幸的是,没有办法编写一个 DateTimeFormatter
支持灵活解析并使用 Joda-Time 的特定输出格式打印的文件。
我正在尝试编写一个 DateTimeFormatter
,它允许我采用多种不同的 String
格式,然后将 String
格式转换为特定类型。由于项目的范围和已经存在的代码,我不能使用不同类型的格式化程序。
例如,我想接受 MM/dd/yyyy
以及 yyyy-MM-dd'T'HH:mm:ss
但是当我打印时我只想打印成 MM/dd/yyyy
格式并在我调用时以格式LocalDate.format(formatter);
有人可以就如何使用 java.time.format.*;
这是我在 org.joda
中的做法:
// MM/dd/yyyy format
DateTimeFormatter monthDayYear = DateTimeFormat.forPattern("MM/dd/yyyy");
// array of parsers, with all possible input patterns
DateTimeParser[] parsers = {
// parser for MM/dd/yyyy format
monthDayYear.getParser(),
// parser for yyyy-MM-dd'T'HH:mm:ss format
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss").getParser()
};
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// use the monthDayYear formatter for output (monthDayYear.getPrinter())
// and parsers array for input (parsers)
.append(monthDayYear.getPrinter(), parsers)
// create formatter (using UTC to avoid DST problems)
.toFormatter()
.withZone(DateTimeZone.UTC);
我还没有在网上找到 good/working 这个例子。
你问的不可能。
DateTimeFormatter
是一个 final
class,所以你不能子 class 它来实现你自己的行为。
构造函数是包私有的,所以不能自己调用。创建 DateTimeFormatter
的唯一方法是使用 DateTimeFormatterBuilder
。请注意,用于创建 DateTimeFormatter
的 static
辅助方法在内部使用 DateTimeFormatterBuilder
,例如
public static DateTimeFormatter ofPattern(String pattern) {
return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
}
DateTimeFormatterBuilder
也是一个 final
class,不能被子classed,并且它没有提供任何方法来提供多种替代格式以供使用,如你所愿。
总之,DateTimeFormatter
已关闭,无法扩展。如果您的代码只能使用 DateTimeFormatter
,那您就倒霉了。
检查字符串的长度
作为替代方案,您可以简单地测试字符串的长度并应用两个格式化程序之一。
DateTimeFormatter fDateOnly = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
DateTimeFormatter fDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME ;
LocalDate ld = null ;
if( input.length() == 10 ) {
try {
ld = LocalDate.parse( input , fDateOnly ) ;
} catch (DateTimeParseException e ) {
…
}
} else if ( input.length() == 19 ) {
try {
LocalDateTime ldt = LocalDateTime.parse( input , fDateTime ) ;
ld = ldt.toLocalDate() ;
} catch (DateTimeParseException e ) {
…
}
} else {
// Received unexpected input.
…
}
String output = ld.format( fDateOnly ) ;
请注意,您可以让 java.time 在生成表示日期时间值的字符串时自动本地化,而不是硬编码特定格式。参见 DateTimeFormatter.ofLocalizedDate。
我已经用 JDK 1.8.0_131 测试了 Mac OS X 和 JDK 1.8.0111 用于 Windows(均有效)。
我创建了一个带有可选部分(由 []
分隔)的 DateTimeFormatter
,以解析这两种情况(MM/dd/yyyy
和 yyyy-MM-dd'T'HH:mm:ss
)。
相同的格式化程序适用于您的案例 (LocalDate
),但下面有一些注意事项。
// parse both formats (use optional section, delimited by [])
DateTimeFormatter parser = DateTimeFormatter.ofPattern("[MM/dd/yyyy][yyyy-MM-dd'T'HH:mm:ss]");
// parse MM/dd/yyyy
LocalDate d1 = LocalDate.parse("10/16/2016", parser);
// parse yyyy-MM-dd'T'HH:mm:ss
LocalDate d2 = LocalDate.parse("2016-10-16T10:20:30", parser);
// parser.format(d1) is the same as d1.format(parser)
System.out.println(parser.format(d1));
System.out.println(parser.format(d2));
输出为:
10/16/2016
10/16/2016
PS: 这仅适用于 LocalDate
。如果我尝试用时间字段格式化一个对象(比如 LocalDateTime
),两种格式都会被使用:
System.out.println(parser.format(LocalDateTime.now()));
这会打印:
06/18/20172017-06-18T07:40:55
请注意,它使用两种模式进行格式化。我的猜测是格式化程序检查对象是否在每个可选部分中都有字段。由于 LocalDate
没有时间字段 (hour/minute/second),第二个模式失败,它只打印第一个 (MM/dd/yyyy
)。但是LocalDateTime
有所有的时间字段,而且两种模式都是有效的,所以都用来格式化。
我的结论是:这不是一个通用的解决方案(如 Joda-Time 的版本),它更像是一个 "lucky" 案例,其中涉及的模式创建了所需的情况。但我不会在所有情况下都依赖它。
无论如何,如果你只是使用LocalDate
,你可以尝试使用这个代码。但是,如果您正在使用其他类型,那么您可能必须对输出使用 另一个 格式化程序,如下所示:
// parser/formatter for month/day/year
DateTimeFormatter mdy = DateTimeFormatter.ofPattern("MM/dd/yyyy");
// parser for both patterns
DateTimeFormatter parser = new DateTimeFormatterBuilder()
// optional MM/dd/yyyy
.appendOptional(mdy)
// optional yyyy-MM-dd'T'HH:mm:ss (use built-in formatter)
.appendOptional(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// create formatter
.toFormatter();
// parse MM/dd/yyyy
LocalDate d1 = LocalDate.parse("10/16/2016", parser);
// parse yyyy-MM-dd'T'HH:mm:ss
LocalDate d2 = LocalDate.parse("2016-10-16T10:20:30", parser);
// use mdy to format
System.out.println(mdy.format(d1));
System.out.println(mdy.format(d2));
// format object with time fields: using mdy formatter to avoid multiple pattern problem
System.out.println(mdy.format(LocalDateTime.now()));
输出为:
10/16/2016
10/16/2016
06/18/2017
可以编写解析部分,并已添加到 ThreeTen-Extra library. The relevant code is here 中,为了清楚起见,将其包含在下面。关键技巧是使用 parseUnresolved()
找出正确的格式:
public static <T> T parseFirstMatching(CharSequence text, TemporalQuery<T> query, DateTimeFormatter... formatters) {
Objects.requireNonNull(text, "text");
Objects.requireNonNull(query, "query");
Objects.requireNonNull(formatters, "formatters");
if (formatters.length == 0) {
throw new DateTimeParseException("No formatters specified", text, 0);
}
if (formatters.length == 1) {
return formatters[0].parse(text, query);
}
for (DateTimeFormatter formatter : formatters) {
try {
ParsePosition pp = new ParsePosition(0);
formatter.parseUnresolved(text, pp);
int len = text.length();
if (pp.getErrorIndex() == -1 && pp.getIndex() == len) {
return formatter.parse(text, query);
}
} catch (RuntimeException ex) {
// should not happen, but ignore if it does
}
}
throw new DateTimeParseException("Text '" + text + "' could not be parsed", text, 0);
}
不幸的是,没有办法编写一个 DateTimeFormatter
支持灵活解析并使用 Joda-Time 的特定输出格式打印的文件。