将时间字符串转换为 ISO 8601 格式
Converting a time String to ISO 8601 format
我正在尝试创建格式类似于 2015-08-20T08:26:21.000Z
的字符串
至 2015-08-20T08:26:21Z
我知道这可以通过一些字符串拆分技术来完成,但我想知道是否有一个优雅的解决方案(代码更改最少)。
以上都是时间字符串,我需要的最后一个是ISO 8601中的日期。 https://www.rfc-editor.org/rfc/rfc3339#section-5.6
我试过几个类似的问题,比如converting a date string into milliseconds in java,但它们并没有真正解决问题。
也尝试使用:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());
但它仍然没有进行任何字符串到字符串的转换。出现以下错误:
23:04:13,829 WARN [RuntimeExceptionMapper] 捕获到 RuntimeException: {}: java.lang.IllegalArgumentException: 无法将给定对象格式化为 Date
有人可以推荐一些图书馆吗?
谢谢。
你的格式不对试试这个:-
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;博士
Instant.parse( "2015-08-20T08:26:21.000Z" )
.toString()
2015-08-20T08:26:21Z
Date-Time格式化程序
如果您只想消除 .000
,则使用 date-time object 解析您的输入字符串值,然后生成该 [= 的新字符串表示形式69=] 不同格式的值。
ISO 8601
顺便说一下,如果这是你的目标,那么问题的标题就没有意义,因为第一句中提到的两个字符串都是有效的 ISO 8601 格式字符串。
2015-08-20T08:26:21.000Z
2015-08-20T08:26:21Z
java.time
Java 8及以后有新的java.time package。这些新的 classes 取代了旧的 java.util.Date/.Calendar & java.text.SimpleDateFormat classes。那些旧的 classes 令人困惑、麻烦且有缺陷。
即时
如果您只需要 UTC 时区,那么您可以使用 Instant
class。 class 表示时间轴上的一个点,不考虑任何特定时区(基本上是 UTC)。
DateTimeFormatter.ISO_INSTANT
调用 Instant 的 toString
generates a String representation of the date-time value using a DateTimeFormatter.ISO_INSTANT
格式化程序实例。此格式化程序自动灵活地调整小数秒。如果该值有整秒,则不会生成小数位(显然是问题想要的)。对于小数秒,数字以 3、6 或 9 为一组出现,根据需要表示高达纳秒分辨率的值。注意:此格式可能超过 ISO 8601 毫秒限制(小数点后 3 位)。
示例代码
这是 Java 8 Update 51.
中的一些示例代码
String output = Instant.parse( "2015-08-20T08:26:21.000Z" ).toString( );
System.out.println("output: " + output );
output: 2015-08-20T08:26:21Z
更改为小数秒,.08
String output = Instant.parse( "2015-08-20T08:26:21.08Z" ).toString( );
output: 2015-08-20T08:26:21.080Z
如果对除 UTC 以外的任何时区感兴趣,请根据 Instant
.
创建 ZonedDateTime
object
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , ZoneId.of( "America/Montreal" ) ) ;
将未知格式的日期 String
转换为使用已知格式的日期 String
可以使用两个 DateFormat
对象来完成 - 一个动态配置为解析格式输入 String
,一个配置为生成格式化输出 String
。对于您的情况,输入 String
格式未指定,必须由调用者提供,但是,输出 String
格式可以配置为使用 ISO 8601 格式,无需额外输入。本质上,生成 ISO 8601 格式的日期 String
输出需要调用者提供两个输入 - 一个包含格式化日期的 String
和另一个包含 SimpleDateFormat
格式的 String
。
这里是描述为 Java 的转换代码(我故意省略了空检查和验证,根据您的代码添加这些):
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);
}
如果您想修改该方法,请注意 SimpleDateFormat
不是线程安全的,如果没有针对多线程代码的解决方法 (ThreadLocal
通常用于为 SimpleDateFormat
) 做这样的解决方法。
另一个 "gotcha" 是在 SimpleDateFormat
对象的构造过程中使用 Locale
- 不要删除 Locale
配置。允许系统选择使用默认值 Locale
是不安全的,因为这是特定于 user/machine 的。如果您确实允许它使用默认值 Locale
,您将 运行 存在暂时性错误的风险,因为您的开发机器使用的 Locale
与最终用户的 Locale
不同.您不必使用我选择的 ENGLISH Locale
,使用不同的 Locale 完全没问题(您应该了解 Locale
的规则并适当修改代码)。然而,没有指定 Locale
和使用系统默认值是不正确的,并且可能会导致许多令人沮丧的时间试图诊断难以捉摸的错误。
请理解此解决方案从 Java 8 开始并不理想,并且包含基于 类 的 JodaTime,例如 Instant
。我选择使用过时的 API 来回答,因为这些是您在问题中似乎关心的问题。如果您正在使用 Java 8,我强烈建议您学习和使用新的 类,因为它们在几乎所有可以想到的方面都有改进。
我正在尝试创建格式类似于 2015-08-20T08:26:21.000Z
的字符串
至 2015-08-20T08:26:21Z
我知道这可以通过一些字符串拆分技术来完成,但我想知道是否有一个优雅的解决方案(代码更改最少)。
以上都是时间字符串,我需要的最后一个是ISO 8601中的日期。 https://www.rfc-editor.org/rfc/rfc3339#section-5.6
我试过几个类似的问题,比如converting a date string into milliseconds in java,但它们并没有真正解决问题。
也尝试使用:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());
但它仍然没有进行任何字符串到字符串的转换。出现以下错误:
23:04:13,829 WARN [RuntimeExceptionMapper] 捕获到 RuntimeException: {}: java.lang.IllegalArgumentException: 无法将给定对象格式化为 Date
有人可以推荐一些图书馆吗?
谢谢。
你的格式不对试试这个:-
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;博士
Instant.parse( "2015-08-20T08:26:21.000Z" )
.toString()
2015-08-20T08:26:21Z
Date-Time格式化程序
如果您只想消除 .000
,则使用 date-time object 解析您的输入字符串值,然后生成该 [= 的新字符串表示形式69=] 不同格式的值。
ISO 8601
顺便说一下,如果这是你的目标,那么问题的标题就没有意义,因为第一句中提到的两个字符串都是有效的 ISO 8601 格式字符串。
2015-08-20T08:26:21.000Z
2015-08-20T08:26:21Z
java.time
Java 8及以后有新的java.time package。这些新的 classes 取代了旧的 java.util.Date/.Calendar & java.text.SimpleDateFormat classes。那些旧的 classes 令人困惑、麻烦且有缺陷。
即时
如果您只需要 UTC 时区,那么您可以使用 Instant
class。 class 表示时间轴上的一个点,不考虑任何特定时区(基本上是 UTC)。
DateTimeFormatter.ISO_INSTANT
调用 Instant 的 toString
generates a String representation of the date-time value using a DateTimeFormatter.ISO_INSTANT
格式化程序实例。此格式化程序自动灵活地调整小数秒。如果该值有整秒,则不会生成小数位(显然是问题想要的)。对于小数秒,数字以 3、6 或 9 为一组出现,根据需要表示高达纳秒分辨率的值。注意:此格式可能超过 ISO 8601 毫秒限制(小数点后 3 位)。
示例代码
这是 Java 8 Update 51.
中的一些示例代码String output = Instant.parse( "2015-08-20T08:26:21.000Z" ).toString( );
System.out.println("output: " + output );
output: 2015-08-20T08:26:21Z
更改为小数秒,.08
String output = Instant.parse( "2015-08-20T08:26:21.08Z" ).toString( );
output: 2015-08-20T08:26:21.080Z
如果对除 UTC 以外的任何时区感兴趣,请根据 Instant
.
ZonedDateTime
object
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , ZoneId.of( "America/Montreal" ) ) ;
将未知格式的日期 String
转换为使用已知格式的日期 String
可以使用两个 DateFormat
对象来完成 - 一个动态配置为解析格式输入 String
,一个配置为生成格式化输出 String
。对于您的情况,输入 String
格式未指定,必须由调用者提供,但是,输出 String
格式可以配置为使用 ISO 8601 格式,无需额外输入。本质上,生成 ISO 8601 格式的日期 String
输出需要调用者提供两个输入 - 一个包含格式化日期的 String
和另一个包含 SimpleDateFormat
格式的 String
。
这里是描述为 Java 的转换代码(我故意省略了空检查和验证,根据您的代码添加这些):
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);
}
如果您想修改该方法,请注意 SimpleDateFormat
不是线程安全的,如果没有针对多线程代码的解决方法 (ThreadLocal
通常用于为 SimpleDateFormat
) 做这样的解决方法。
另一个 "gotcha" 是在 SimpleDateFormat
对象的构造过程中使用 Locale
- 不要删除 Locale
配置。允许系统选择使用默认值 Locale
是不安全的,因为这是特定于 user/machine 的。如果您确实允许它使用默认值 Locale
,您将 运行 存在暂时性错误的风险,因为您的开发机器使用的 Locale
与最终用户的 Locale
不同.您不必使用我选择的 ENGLISH Locale
,使用不同的 Locale 完全没问题(您应该了解 Locale
的规则并适当修改代码)。然而,没有指定 Locale
和使用系统默认值是不正确的,并且可能会导致许多令人沮丧的时间试图诊断难以捉摸的错误。
请理解此解决方案从 Java 8 开始并不理想,并且包含基于 类 的 JodaTime,例如 Instant
。我选择使用过时的 API 来回答,因为这些是您在问题中似乎关心的问题。如果您正在使用 Java 8,我强烈建议您学习和使用新的 类,因为它们在几乎所有可以想到的方面都有改进。