单一日期格式化程序,用于分析具有不同语法的日期



我有一个java程序。在我的java程序中,输入将是不同格式的日期字符串,如以下

a) 2021-10-09T08:00:01.111Z ( with millisecond)
b) 2021-10-09T08:00:01Z ( without milliseconds)
c) 2021-10-09T08:00Z ( no seconds )
d) 2021-10-09T08Z ( no minutes ) 

目前我使用的是内置的日期格式化程序DateTimeFormatter.ISO_OFFSET_date_TIME。然而,当我运行我的示例代码段程序时,失败了

以下是我的示例程序

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
public class Tester2 {
public static void main(String[] args) {

OffsetDateTime t1 = OffsetDateTime.parse("2021-10-09T08:00:01.111Z");;
System.out.println(t1.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

OffsetDateTime t2 = OffsetDateTime.parse("2021-10-09T08:00:01Z");;
System.out.println(t2.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

OffsetDateTime t3 = OffsetDateTime.parse("2021-10-09T08:00Z");;
System.out.println(t3.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

OffsetDateTime t4 = OffsetDateTime.parse("2021-10-09T08Z");;
System.out.println(t4.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}
}

然而,当我运行我的程序时,它会失败,并产生以下输出。

2021-10-09T08:00:01.111Z
2021-10-09T08:00:01Z
2021-10-09T08:00:00Z
Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-10-09T08Z' could not be parsed at index 13
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954)
at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:404)
at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:389)
at test.Tester2.main(Tester2.java:20)

以下是我想要的输出

2021-10-09T08:00:01.111Z
2021-10-09T08:00:01Z
2021-10-09T08:00:00Z
2021-10-09T08:00:00Z

是否有任何java内置的数据格式化程序可以帮助我实现所需的输出。如果没有这种日期格式化程序,你能帮我写一个新的日期格式化程序吗?欢迎采用其他解决方案。

DataTimeFormatter支持具有[]字符的可选解析模式。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH[:mm[:ss[.SSS]]]X");
OffsetDateTime t1 = OffsetDateTime.parse("2021-10-09T08:00:01.111Z", formatter);
System.out.println(t1.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
OffsetDateTime t2 = OffsetDateTime.parse("2021-10-09T08:00:01Z", formatter);
System.out.println(t2.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
OffsetDateTime t3 = OffsetDateTime.parse("2021-10-09T08:00Z", formatter);
System.out.println(t3.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
OffsetDateTime t4 = OffsetDateTime.parse("2021-10-09T08Z", formatter);
System.out.println(t4.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));

输出是您所要求的:

2021-10-09T08:00:01.111Z
2021-10-09T08:00:01Z
2021-10-09T08:00:00Z
2021-10-09T08:00:00Z

一方面,Java缺乏解析部分日期格式的功能,这可能看起来很奇怪(我在每个异构项目中都面临这样的问题(,然而,另一方面,当我们解析部分日期形式时,我们需要以某种方式补偿缺失的字段,而问题是这种补偿/启发式取决于特定项目,系统之间的特定交互,请查看下面的PoC,希望它能有所帮助:

import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE;
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
public class DateTimeFormats {
public static final DateTimeFormatter ISO_LOCAL_TIME = new DateTimeFormatterBuilder()
.appendValue(HOUR_OF_DAY, 2)
.optionalStart()
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(NANO_OF_SECOND, 0, 9, true)
.toFormatter();
public static final DateTimeFormatter ISO_OPTIONAL_TIME = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendLiteral('T')
.append(ISO_LOCAL_TIME)
.parseStrict()
.toFormatter();
public static final DateTimeFormatter ISO_OPTIONAL_OFFSET = new DateTimeFormatterBuilder()
.appendOffsetId()
.toFormatter();
public static final DateTimeFormatter ISO_LOCAL_DATE_OPTIONAL_TIME = new DateTimeFormatterBuilder()
.append(ISO_LOCAL_DATE)
.appendOptional(ISO_OPTIONAL_TIME)
.toFormatter();
public static final DateTimeFormatter ISO_DATE_OPTIONAL_TIME = new DateTimeFormatterBuilder()
.append(ISO_LOCAL_DATE_OPTIONAL_TIME)
.appendOptional(ISO_OPTIONAL_OFFSET)
.optionalStart()
.appendLiteral('[')
.parseCaseSensitive()
.appendZoneRegionId()
.appendLiteral(']')
.toFormatter()
// compensation
.withZone(ZoneId.systemDefault())
.withChronology(IsoChronology.INSTANCE);
public static OffsetDateTime offsetDateTime(CharSequence text) {
return offsetDateTime(text, ISO_DATE_OPTIONAL_TIME);
}
public static OffsetDateTime offsetDateTime(CharSequence text, DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
return formatter.parse(text, DateTimeFormats::offsetDateTime);
}
public static OffsetDateTime offsetDateTime(TemporalAccessor temporal) {
try {
LocalDate date = LocalDate.from(temporal);
Optional<LocalTime> time = Optional.ofNullable(temporal.query(TemporalQueries.localTime()));
Optional<ZoneOffset> offset = Optional.ofNullable(temporal.query(TemporalQueries.offset()));
Optional<ZoneId> zone = Optional.ofNullable(temporal.query(TemporalQueries.zoneId()));
// compensation
LocalDateTime result = LocalDateTime.of(date, time.orElse(LocalTime.MIN));
if (offset.isPresent()) {
return OffsetDateTime.of(result, offset.get());
} else if (zone.isPresent()) {
return ZonedDateTime.of(result, zone.get())
.toOffsetDateTime();
}
return result
// compensation
.atZone(ZoneId.systemDefault())
.toOffsetDateTime();
} catch (DateTimeException ex) {
throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " +
temporal + " of type " + temporal.getClass().getName(), ex);
}
}
}
System.out.println(offsetDateTime("2021-10-09T08:00:01.1111111Z"));
System.out.println(offsetDateTime("2021-10-09T08:00:01.111Z"));
System.out.println(offsetDateTime("2021-10-09T08:00:01Z"));
System.out.println(offsetDateTime("2021-10-09T08:00Z"));
System.out.println(offsetDateTime("2021-10-09T08Z"));
System.out.println(offsetDateTime("2021-10-09Z"));
System.out.println(offsetDateTime("2021-10-09[Australia/Melbourne]"));
System.out.println(offsetDateTime("2021-10-09T08:00:01.111[Australia/Melbourne]"));
System.out.println(offsetDateTime("2021-10-09T08:00:01[Australia/Melbourne]"));
System.out.println(offsetDateTime("2021-10-09T08:00[Australia/Melbourne]"));
System.out.println(offsetDateTime("2021-10-09T08[Australia/Melbourne]"));
System.out.println(offsetDateTime("2021-10-09[Australia/Melbourne]"));
2021-10-09T08:00:01.111111100Z
2021-10-09T08:00:01.111Z
2021-10-09T08:00:01Z
2021-10-09T08:00Z
2021-10-09T08:00Z
2021-10-09T00:00Z
2021-10-09T00:00+11:00
2021-10-09T08:00:01.111+11:00
2021-10-09T08:00:01+11:00
2021-10-09T08:00+11:00
2021-10-09T08:00+11:00
2021-10-09T00:00+11:00

我曾经不得不处理从字符串中解析日期的问题,这些字符串可以是事先不知道的任何格式。我通过以下方式解决了这个问题。我准备了一个配置文件,每行都包含我想要支持的日期格式。当String出现时,我试图用文件中的每种格式解析它,直到我成功或浏览了所有可用的格式。请注意,在这种情况下,格式的顺序很重要,因为如果您希望欧洲格式优先于美国格式,您可以将欧洲格式放在第一位,反之亦然。无论如何,我写了一篇小文章,详细解释了这个想法:Java 8 Java.time包:解析迄今为止的任何字符串

最新更新