java.time DateTimeFormatter 模式,用于时区偏移量

2022-09-02 00:58:26

我正在尝试解析:其中是UTC的偏移量。在 Java 8 中使用 java.time DateTimeFormatter2014-05-02-10.45.05.993280-5:00-5:00

对于第一位,我有以下内容:但是,我无法弄清楚模式应该是什么来解析偏移量。yyyy-MM-dd-HH.mm.ss.SSSSSS

如果我的偏移量为4位数字(-05:00),我可以使用:,但这不适用于3位数字。yyyy-MM-dd-HH.mm.ss.SSSSSSxxx

有什么想法吗?


答案 1

使用大写字母 X 而不是 x,因此使用 XXX。不同之处在于,大 X 可以将输入字母“Z”识别为 UTC 偏移量 +00:00,而小模式字母 X 则不能。

建议的模式:

yyyy-MM-dd-HH.mm.ss.SSSSSSXXX

另请注意以下 JDK 错误

java.time.format.DateTimeFormatter 无法解析具有个位数小时的偏移量

更新:

我现在已经在错误日志中测试了描述的解决方法。

String input = "2014-05-02-10.45.05.993280-5:00";
DateTimeFormatter f = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS")
        .parseLenient()
        .appendOffset("+HH:MM", "Z")
        .toFormatter();
System.out.println(f.parse(input, ZonedDateTime::from));

但它会引发一个异常:

线程“main” java.time.format.DateTimeParseException 中的异常:文本 '2014-05-02-10.45.05.993280-5:00' 无法在索引 26 处解析 java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849) at HelloWorld.main(HelloWorld.java:16)

因此,宽容的解析也无济于事。因此,现在只剩下三个选项供您选择:

  • 使用 bug 报告器建议的解决方法: [...] 解决方法是单独解析日期/时间,使用手动编码的偏移量解析器,并将 LocalDateTime 与手动解析的偏移量相结合。这不是一件容易的事。

  • 尝试您自己的专用字符串预处理。如果您有固定的格式,则可以尝试在位置26处插入零位(如果总输入长度为一位数字太小)。

  • 或者,您可以使用可以执行此操作的外部库。我的库Time4J(v4.0)可以做到这一点,如果你愿意添加一个额外的依赖项。请参阅此代码:

String input = "2014-05-02-10.45.05.993280-5:00";
ZonalDateTime zdt =
    ZonalDateTime.parse(
        input,
        Moment.localFormatter("yyyy-MM-dd-HH.mm.ss.SSSSSSXXX", PatternType.CLDR));
System.out.println(zdt); // 2014-05-02T10:45:05,993280UTC-05:00
ZonedDateTime result = zdt.toTemporalAccessor();

更新:根据JDK-bug-status,Java-9已经修复了该错误,但是Java-8的向后移植似乎不可用。


答案 2

所有的答案都很好。java8+ 具有以下用于解析和格式化时区的模式:、 、 、 、 、 。VzOXxZ

以下是根据文档中的规则进行解析的:

   Symbol  Meaning                     Presentation      Examples
   ------  -------                     ------------      -------
   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

但是格式化怎么样?下面是一个日期(假设 )的示例,它显示了不同格式模式的这些模式行为:ZonedDateTime

// The helper function:
static void printInPattern(ZonedDateTime dt, String pattern) {
    System.out.println(pattern + ": " + dt.format(DateTimeFormatter.ofPattern(pattern)));
}        

// The date:
String strDate = "2020-11-03 16:40:44 America/Los_Angeles";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzzz");
ZonedDateTime dt = ZonedDateTime.parse(strDate, format);
// 2020-11-03T16:40:44-08:00[America/Los_Angeles]

// Rules:
// printInPattern(dt, "V");     // exception!
printInPattern(dt, "VV");       // America/Los_Angeles
// printInPattern(dt, "VVV");   // exception!
// printInPattern(dt, "VVVV");  // exception!
printInPattern(dt, "z");        // PST
printInPattern(dt, "zz");       // PST
printInPattern(dt, "zzz");      // PST
printInPattern(dt, "zzzz");     // Pacific Standard Time
printInPattern(dt, "O");        // GMT-8
// printInPattern(dt, "OO");    // exception!
// printInPattern(dt, "OO0");   // exception!
printInPattern(dt, "OOOO");     // GMT-08:00
printInPattern(dt, "X");        // -08
printInPattern(dt, "XX");       // -0800
printInPattern(dt, "XXX");      // -08:00
printInPattern(dt, "XXXX");     // -0800
printInPattern(dt, "XXXXX");    // -08:00
printInPattern(dt, "x");        // -08
printInPattern(dt, "xx");       // -0800
printInPattern(dt, "xxx");      // -08:00
printInPattern(dt, "xxxx");     // -0800
printInPattern(dt, "xxxxx");    // -08:00
printInPattern(dt, "Z");        // -0800
printInPattern(dt, "ZZ");       // -0800
printInPattern(dt, "ZZZ");      // -0800
printInPattern(dt, "ZZZZ");     // GMT-08:00
printInPattern(dt, "ZZZZZ");    // -08:00

在正偏移的情况下,符号字符在任何地方(现在有的地方)使用,并且从不省略。+-

这很好地适用于新类型。如果您要将这些用于或 - 并非所有类型都会工作,因为这些类型已损坏(因此标记为已弃用,请不要使用它们)java.timejava.util.Datejava.util.Calendar