如何在 Java 中格式化 ISO-8601 字符串?

How to format an ISO-8601 string in Java?

如何将 ISO-8601 字符串 2020-02-10T22:55:13-08:00 格式化为 1:30pm 等自定义格式?我一直收到 unparseable date 异常。我的代码片段如下:

    String string = "2020-02-10T22:55:13-08:00";
    SimpleDateFormat sdfSource = new SimpleDateFormat("YYYY-MM-DD'T'HH:mm:ss'Z'", Locale.getDefault());
    SimpleDateFormat sdfTarget = new SimpleDateFormat("h:mma", Locale.getDefault());
    try {
        Date date = sdfSource.parse(string);
        String createdAt = sdfTarget.format(date);
        System.out.println(createdAt);
    } catch (ParseException e) {
      e.printStackTrace();
    }

sdfSource 中使用 X(不带引号)代替 'Z'(带引号)。这将解决问题。由于您使用的是引号,因此输入中应包含文字 Z。其次,您需要使用 X 而不是 Z,因为 X 表示 RFC822 时区,这意味着小时和分钟之间没有冒号。您的示例值在小时和分钟之间有冒号。

顺便说一句:您可以切换到 Java 8 中引入的新日期和时间 类,包括它的 parser/formatter。它比 SimpleDateFormat 更通用。它还使用预定义格式处理更多开箱即用的用例,因此您不必创建自己的解析器。 ...就像你现在做的那样。

    private String  getZonedDateTime(String startTime,String inExpectedTimeZone){
        return ZonedDateTime
                .parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"))
                .withZoneSameInstant(ZoneId.of(inExpectedTimeZone)).format(DateTimeFormatter.ofPattern("hh:mm a"));
    }

在上面的方法中,只需传递 zulu 字符串和预期时间,您希望在其中使用 java 8 ZonedDateTime 和 DateTimeFormatter 解析它的值。

如果您的 Java 8 或以上,您可以使用 LocalDateTime,如下所示。

编辑 根据@Andreas 和@OleV.V. 的评论,我想到了4种编译方式,方便参考。其中 2 个使用 OffsetDateTime,2 个使用 @Sriram 的 ZonedDateTime 答案。另外,根据一个人的开头是字符串还是 LocalDateTime

String string = "2020-02-10T22:55:13-08:00";
DateTimeFormatter inF = DateTimeFormatter.ISO_DATE_TIME;
String desiredZoneId = "Z";
int desiredOffset = 0;

DateTimeFormatter toF = DateTimeFormatter.ofPattern( "h:mm a" );
LocalDateTime ldt = LocalDateTime.parse(string.trim(), inF );

/* Prints -> "ldt.atOffset: 6:55 AM" */
/* 1. If one already has a LocalDateTime. Drawback: One needs to know the offset in the time string. */
System.out.println( "ldt.atOffset: " + ldt.atOffset( ZoneOffset.ofHours( -8 ) ).withOffsetSameInstant( ZoneOffset.ofHours( desiredOffset ) ).format( toF ) );

/* Prints -> "ldt.atZone: 6:55 AM" */
/* 2. If one already has a LocalDateTime. Drawback: One needs to know the offset in the time string. */
System.out.println( "ldt.atZone: " + ldt.atZone( ZoneId.of( "-08:00" ) ).withZoneSameInstant( ZoneId.of( desiredZoneId ) ).format( toF ) );

/* Prints -> "odt: 6:55 AM" */ 
/* 3. Using OffsetDateTime. */
OffsetDateTime odt = OffsetDateTime.parse( string, inF );
System.out.println( "odt: " + odt.withOffsetSameInstant( ZoneOffset.ofHours( desiredOffset ) ).format( toF ) );

/* Prints -> "zdt: 6:55 AM" */
/* 4. Using ZonedDateTime. */
String zdt = ZonedDateTime.parse( string, DateTimeFormatter.ISO_DATE_TIME )
.withZoneSameInstant( ZoneId.of( desiredZoneId ) ).format( toF );
System.out.println( "zdt: " + zdt );