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

4

我正在尝试将标准的ISO 8601格式2014-09-11T21:28:29.429209Z转换为美好的MMM d yyyy hh:mm z格式,但是我的当前代码失败了。

public void setCreatedAt( String dateTime ) {

    LocalDate newDateTime = LocalDate.parse(dateTime);

    try {
        DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a z");
        createdAt = newDateTime.format(format); 
    }
    catch (Exception e) {
    }

}

我正在从API接收时间和日期。


@RaminOmrani 2014-09-11T21:28:29.429209Z 中的 "z" 代表协调世界时。 - Pocari
你尝试过使用Joda Time API吗? - Bhupi
@Bhupi 没有理由转换到 joda time 来解决这个问题。事实上,很可能你会面临相同的选择。 - YoYo
3个回答

4
一个java.time.LocalDate指的是“ISO-8601日历系统中没有时区的日期,例如2007-12-03”,因此那里的信息不足。请改用java.time.ZonedDateTime
此外,吞掉异常会使故障排除变得更加困难。如果您不打算处理异常,则完全不要捕获它,捕获并将其重新抛出包装在RuntimeException中,或者至少记录它(e.printStackTrace()等)。

成功了!谢谢!我肯定需要在异常处理方面努力。感谢您的提示! :) - Pocari
1
请注意,LocalDate 无法保存时间组件,只能保存日期组件。 - YoYo

3

简而言之

Instant.parse( "2014-09-11T21:28:29.429209Z" )
       .atZone( ZoneId.of( "Asia/Kolkata" ) )
       .format( DateTimeFormatter.ofPattern("MMM d uuuu hh:mm a z" , Locale.US ) )

请看此处的在 IdeOne.com 上运行的代码

详情

Jakber的答案在技术上可行,但具有误导性。

ZonedDateTime 用于时区

ZonedDateTime 应该具有指定时区,例如 America/MontrealPacific/Auckland

但是,此输入字符串缺乏时区。结尾处的 Z 是短语 Zulu 的缩写,表示协调世界时 (UTC),换句话说,是与 UTC 偏移量为零小时 (+00:00)。

时区是特定区域的偏移量的历史集合,包括即将发生的偏移更改的规则,如夏令时(DST)等异常情况。

Instant

输入的字符串最好解析为 Instant,它表示时间轴上的一个时刻,始终处于协调世界时 (UTC)。这个类直接解析这种特定的 ISO 8601 格式的字符串,因此不需要格式化模式。

Instant instant = Instant.parse( "2014-09-11T21:28:29.429209Z" );

调整时区

您可以调整时区以获取一个ZonedDateTime

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z );

生成字符串

要生成与输入相同格式的字符串,只需调用Instant::toString()即可。

String output = instant.toString() ;

如果您需要使用某个地区的墙钟时间进行自定义格式,请使用DateTimeFormatter与您的自定义格式模式。同时使用ZonedDateTime。作为良好的习惯,始终指定所需的语言环境,以便在翻译和格式化中考虑人类语言和文化规范。

DateTimeFormatter f = DateTimeFormatter.ofPattern("MMM d uuuu hh:mm a z" , Locale.US );
String output = zdt.format( f ); 

关于java.time

java.time框架内置于Java 8及以上版本。这些类取代了老旧的传统日期时间类,例如java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在处于 维护模式,建议迁移到 java.time 类。

要了解更多信息,请参见 Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是 JSR 310

您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,也不需要 java.sql.* 类。

如何获取 java.time 类?

ThreeTen-Extra项目通过添加额外的类扩展了java.time。该项目是java.time可能未来增加内容的试验场。您可能会在此处找到一些有用的类,如Interval, YearWeek, YearQuarter更多


0
public void setCreatedAt(String dateTime) {
    SimpleDateFormat sdfSource = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
    SimpleDateFormat sdfTarget = new SimpleDateFormat("MMM d yyyy hh:mm a z", Locale.getDefault());
    try {
        Date date = sdfSource.parse(dateTime);
        String createdAt = sdfTarget.format(date);
        Log.e(TAG, "setCreatedAt: createdAt " + createdAt);
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

请不要教年轻人使用早已过时且臭名昭著的SimpleDateFormat类。至少不要将其作为第一选择。而且不要毫无保留地使用它。我们在java.time,现代Java日期和时间API中有更好的选择,以及它的DateTimeFormatter。OP甚至已经在使用它了。 - Ole V.V.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接