【问题标题】:How to handle all Zone Offset in one DateTimeFormater Java 8如何在一个 DateTimeFormatter Java 8 中处理所有区域偏移
【发布时间】:2017-06-23 08:48:00
【问题描述】:

我需要为以下有效日期创建一个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();

date1date8 的所有日期都可以正常工作,但在尝试解析最后两个日期时我得到了DateTimeParseException

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

为了解析我使用的日期如下。

LocalDateTime.parse(date1, DATE_TIME_FORMATTER);

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 模式时,我无法理解为什么我的最后两个日期失败了。

【问题讨论】:

    标签: java-8 java-time datetime-parsing zoneddatetime


    【解决方案1】:

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

    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 个示例日期时间字符串。

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

    【讨论】:

    • @Eugene 但我们仍然需要找出 Java 这样做的原因。
    • 顺序有一点逻辑性。正则表达式不能直接比较,仍然"cats".replaceFirst("cat|cats", "bird") 产生birds 而相反的顺序,"cats".replaceFirst("cats|cat", "bird"),只产生bird。日期时间格式化程序甚至没有像正则表达式那样给我们一个 OR,只是一系列部分,每个部分都是可选的,所以我认为除了按顺序尝试它们之外别无选择。
    【解决方案2】:

    另一种选择是使用可选部分,由[] 和各自的offset patternsVVx)分隔:

    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]fraction-of-seconds 字段中接受 完全 6 位数字(或零位数字,因为它是可选部分),而appendFraction 接受从 0 到 6 位的任何数量。要获得完全相同的行为,您必须使用 DateTimeFormatterBuilder:

    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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-26
      • 2021-12-05
      • 2015-08-23
      • 1970-01-01
      • 2017-12-31
      • 2020-01-19
      • 2015-02-04
      • 1970-01-01
      相关资源
      最近更新 更多