3

我需要DateTimeFormatter为以下有效日期创建一个。

  String date1 = "2017-06-20T17:25:28";
  String date2 = "2017-06-20T17:25:28.477777";
  String date3 = "2017-06-20T17:25:28.477777Z";
  String date4 = "2017-06-20T17:25:28.477777UTC";
  String date5 = "2017-06-20T17:25:28.477777-05";
  String date6 = "2017-06-20T17:25:28.477777+05";
  String date7 = "2017-06-20T17:25:28.477777+05:30";
  String date8 = "2017-06-20T17:25:28.477777-05:30";
  String date9 = "2017-06-20T17:25:28.477777+0530";
  String date10 = "2017-06-20T17:25:28.477777-0530";

我已经尝试了以下日期时间格式化程序,但是对于最后两个日期(date9date10)失败了。

private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
    .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
                        .optionalStart().appendZoneId().optionalEnd()
                        .optionalStart().appendOffset("+HH", "+00").optionalEnd()
                        .optionalStart().appendOffset("+HH:mm", "+00:00").optionalEnd()
                        .optionalStart().appendOffset("+HHmm", "+0000").optionalEnd().toFormatter();

所有日期都date1可以date8正常工作,但我DateTimeParseException在尝试解析最后两个日期时得到一个:

线程“主”java.time.format.DateTimeParseException 中的异常:无法解析文本“2017-06-20T17:25:28.477777+0530”,在索引 29 处找到未解析的文本

为了解析我正在使用的日期。

LocalDateTime.parse(date1, DATE_TIME_FORMATTER);

Offset From 的有效模式OffsetIdPrinterParser

static final class OffsetIdPrinterParser implements DateTimePrinterParser {
        static final String[] PATTERNS = new String[] {
            "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS",
        };  // order used in pattern builder

当我使用有效的 ZoneOffset 模式时,我无法理解为什么我的最后两个日期失败了。

4

2 回答 2

5

只需颠倒可选部分的顺序:

private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
        .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
        .optionalStart().appendZoneId().optionalEnd()
        .optionalStart().appendOffset("+HHmm", "+0000").optionalEnd()
        .optionalStart().appendOffset("+HH:mm", "+00:00").optionalEnd()
        .optionalStart().appendOffset("+HH", "+00").optionalEnd()
        .toFormatter();

这会解析所有 10 个示例日期时间字符串。

我不太确定它为什么会起作用。我想它现在正在尝试+HHmmbefore +HH,这确保它在有四个数字时得到所有四位数字,而不是让最后两个数字不被解析。

于 2017-06-23T09:24:33.683 回答
4

另一种选择是使用可选部分,由 分隔[],以及相应的偏移模式VVx):

DATE_TIME_FORMATTER = DateTimeFormatter
                         // pattern with optional sections: fraction of seconds and offsets
                         .ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSSSSS][VV][x][xx][xxx]");

每对[]相当于一个optionalStartoptionalEnd节。请注意,我还必须将大写S(秒的小数部分)包含为可选,以解析该字段不存在的情况。

其他模式 (VVx) 对应于您需要的各种偏移量。从javadoc

Pattern  Count  Equivalent builder methods
-------  -----  --------------------------
  VV      2      appendZoneId()
  x       1      appendOffset("+HHmm","+00")
  xx      2      appendOffset("+HHMM","+0000")
  xxx     3      appendOffset("+HH:MM","+00:00")

这适用于您的所有输入日期。


唯一的区别是在小数部分[.SSSSSS]字段中只接受6位数字(或零位数字,因为它是一个可选部分),而接受从 0 到 6 位数字的任何数量。要获得完全相同的行为,您必须使用:appendFractionDateTimeFormatterBuilder

DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
    // date and time
    .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
    // fraction of seconds, from 0 to 6 digits
    .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
    // optional offset patterns
    .appendPattern("[VV][x][xx][xxx]")
    .toFormatter();
于 2017-06-25T03:24:57.617 回答