Java 将时间字符串转换为ISO 8601格式

Java 将时间字符串转换为ISO 8601格式,java,string,time,Java,String,Time,我正在尝试创建一个字符串,格式类似于2015-08-20T08:26:21.000Z to2015-08-20T08:26:21Z 我知道这可以通过一些字符串拆分技术来实现,但我想知道是否有一个优雅的解决方案(只需对代码进行最小的更改) 以上两个都是时间字符串,我需要的最后一个是ISO8601中的日期 我试过一些类似的问题,比如,但它们实际上并不能解决问题 还尝试使用: SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ

我正在尝试创建一个字符串,格式类似于2015-08-20T08:26:21.000Z
to2015-08-20T08:26:21Z

我知道这可以通过一些字符串拆分技术来实现,但我想知道是否有一个优雅的解决方案(只需对代码进行最小的更改)

以上两个都是时间字符串,我需要的最后一个是ISO8601中的日期

我试过一些类似的问题,比如,但它们实际上并不能解决问题

还尝试使用:

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());
但它仍然不进行任何字符串到字符串的转换。获取以下错误:

23:04:13829警告[RuntimeExceptionMapper]捕获的RuntimeException:{}:java.lang.IllegalArgumentException:无法将给定对象格式化为日期

有人可以推荐的图书馆吗


谢谢

您的格式不正确,请尝试以下方法:-

try {
        String s = "2015-08-20T08:26:21.000Z";
         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
    Date d = df.parse(s);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
        System.out.println(sdf.format(d));
    } catch (ParseException e) {
        e.printStackTrace();
    }
tl;博士 2015-08-20T08:26:21Z

日期时间格式化程序 如果您只想消除
.000
,则使用日期时间对象解析输入字符串值,然后以不同格式生成该日期时间值的新字符串表示形式

ISO 8601 顺便说一下,如果这是您的目标,那么问题的标题就没有意义了,因为第一句中提到的两个字符串都是有效的格式化字符串

  • 2015-08-20T08:26:21.000Z
  • 2015-08-20T08:26:21Z
java.time Java8及更高版本具有新的功能。这些新类取代了旧的java.util.Date/.Calendar&java.text.SimpleDataFormat类。那些旧的类令人困惑、麻烦且有缺陷

瞬间 如果您只需要UTC时区,则可以使用该类。此类表示时间线上的一个点,不考虑任何特定时区(基本上是UTC)

DateTimeFormatter.ISO\u INSTANT
调用瞬间会使用格式化程序实例生成日期时间值的字符串表示形式。此格式化程序在小数秒左右自动灵活。如果该值有整秒,则不会生成小数点(显然是问题想要的)。对于分数秒,数字以3、6或9为一组显示,以表示高达纳秒分辨率的值。注:此格式可能超过ISO 8601的毫秒限制(小数点后3位)

示例代码 下面是Java8Update51中的一些示例代码

String output = Instant.parse( "2015-08-20T08:26:21.000Z" ).toString( );
System.out.println("output: " + output );
输出:2015-08-20T08:26:21Z

更改为小数秒,
.08

String output = Instant.parse( "2015-08-20T08:26:21.08Z" ).toString( );
输出:2015-08-20T08:26:21.080Z

如果对UTC以外的任何时区感兴趣,则从该
即时
创建一个对象

ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , ZoneId.of( "America/Montreal" ) ) ;

可以使用两个
DateFormat
对象将未知格式的日期
字符串
转换为使用已知格式的日期
字符串
,一个动态配置为解析输入
字符串
的格式,另一个配置为生成格式化输出
字符串
。对于您的情况,输入
String
格式未指定,必须由调用者提供,但是,输出
String
格式可以配置为使用ISO 8601格式,而无需额外输入。本质上,生成ISO 8601格式化日期
字符串
输出需要调用者提供两个输入-一个
字符串
包含格式化日期,另一个
字符串
包含
SimpleDataFormat
格式

以下是描述为Java代码的转换(我故意省略了空检查和验证,根据您的代码添加它们):

如果要修改该方法,请注意,
SimpleDateFormat
不是线程安全的,如果没有多线程代码的变通方法,您不应该在静态上下文中使用它(
ThreadLocal
通常用于
SimpleDateFormat
的变通方法)

另一个“问题”是在构建
SimpleDataFormat
对象期间使用
Locale
——不要删除
Locale
配置。允许系统选择使用默认的
区域设置是不安全的,因为这是用户/机器特定的。如果您允许它使用默认的
区域设置
,您将面临暂时性错误的风险,因为您的开发机器使用的
区域设置
与最终用户的
区域设置
不同。您不必使用我选择的英语
区域设置
,使用不同的区域设置完全可以(您应该理解该
区域设置
的规则,并根据需要修改代码)。然而,no
Locale
的规范和系统默认值的使用是不正确的,并且可能会导致在诊断难以捉摸的bug时花费很多令人沮丧的时间


请理解,对于Java8和包含基于JodaTime的类(如
Instant
),此解决方案并不理想。我选择使用过时的API来回答问题,因为在你的问题中,这些似乎是你所关心的。如果您使用的是Java 8,我强烈建议您学习和使用这些新类,因为它们在几乎所有可能的方面都是一种改进。

使用。请参阅:输入和输出都是字符串。但这些字符串实际上代表不同的时区。DateFormat进行字符串到日期和日期到字符串的转换。您需要字符串到字符串的转换。因此,您可以使用DateFormat进行字符串到日期的转换,而使用另一个进行日期到字符串的转换。不,它们并不代表不同的时区。一个有毫秒部分,另一个没有。这是唯一的区别。最后一个Z表示祖鲁时间,即UTC时区.So org.joda.time.format.DateTimeFormatter?@CodeMonkey所以您的目标是消除
.000
?您的标题很混乱,因为f中的两个日期时间字符串
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , ZoneId.of( "America/Montreal" ) ) ;
private String formatDateAsIso8601(final String inputDateAsString, final String inputStringFormat) throws ParseException {

     final DateFormat iso8601DateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.ENGLISH);
     iso8601DateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));

     final DateFormat inputDateFormatter = new SimpleDateFormat(inputStringFormat, Locale.ENGLISH);
     final Date inputDate = inputDateFormatter.parse(inputDateAsString);

     return iso8601DateFormatter.format(inputDate);
}