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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32163678/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:06:03  来源:igfitidea点击:

Converting a time String to ISO 8601 format

javastringtime

提问by CodeMonkey

I am trying to create a String in a format like 2015-08-20T08:26:21.000Z
to 2015-08-20T08:26:21Z

我正在尝试以2015-08-20T08:26:21.000Z
2015-08-20T08:26:21Z等格式创建字符串

I know it can be done with some String splitting techniques, but i am wondering if there is an elegant solution for that (with minimal code changes).

我知道它可以通过一些字符串拆分技术来完成,但我想知道是否有一个优雅的解决方案(代码更改最少)。

Both of the above are time strings, the final one which i need is Date in ISO 8601 . http://tools.ietf.org/html/rfc3339#section-5.6

以上都是时间字符串,我需要的最后一个是 ISO 8601 中的 Date 。http://tools.ietf.org/html/rfc3339#section-5.6

I have tried a few similar questions like converting a date string into milliseconds in javabut they dont actually solve the purpose.

我尝试了一些类似的问题,比如在 java 中将日期字符串转换为毫秒,但它们实际上并没有解决目的。

Also tried using :

还尝试使用:

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());

But it still does not do any String to String conversions. Getting the following error:

但它仍然不进行任何字符串到字符串的转换。得到以下错误:

23:04:13,829 WARN [RuntimeExceptionMapper] caught RuntimeException: {}: java.lang.IllegalArgumentException: Cannot format given Object as a Date

23:04:13,829 警告 [RuntimeExceptionMapper] 捕获了运行时异常:{}:java.lang.IllegalArgumentException:无法将给定的对象格式化为日期

Is there some library which someone can suggest ?

有人可以推荐一些图书馆吗?

Thanks.

谢谢。

采纳答案by Basil Bourque

tl;dr

tl;博士

Instant.parse( "2015-08-20T08:26:21.000Z" )
       .toString()

2015-08-20T08:26:21Z

2015-08-20T08:26:21Z

Date-Time Formatter

日期时间格式化程序

If all you want to do is eliminate the .000, then use date-time objects to parse your input string value, then generate a new string representation of that date-time value in a different format.

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

ISO 8601

ISO 8601

By the way, if that is your goal, the Question's title make no sense as both strings mentioned in the first sentence are valid ISO 8601formatted strings.

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

  • 2015-08-20T08:26:21.000Z
  • 2015-08-20T08:26:21Z
  • 2015-08-20T08:26:21.000Z
  • 2015-08-20T08:26:21Z

java.time

时间

Java 8 and later has the new java.time package. These new classes supplant the old java.util.Date/.Calendar & java.text.SimpleDateFormat classes. Those old classes were confusing, troublesome, and flawed.

Java 8 及更高版本具有新的java.time 包。这些新类取代了旧的 java.util.Date/.Calendar 和 java.text.SimpleDateFormat 类。那些旧的课程很混乱,很麻烦,而且有缺陷。

Instant

立即的

If all you want is UTC time zone, then you can use the Instantclass. This class represents a point along the timeline without regard to any particular time zone (basically UTC).

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

DateTimeFormatter.ISO_INSTANT

DateTimeFormatter.ISO_INSTANT

Calling an Instant's toStringgenerates a String representation of the date-time value using a DateTimeFormatter.ISO_INSTANTformatter instance. This formatter is automatically flexible about the fractional second. If the value has a whole second, no decimal places are generated (apparently what the Question wants). For a fractional second, digits appear in groups of 3, 6, or 9, as needed to represent the value up to nanosecond resolution. Note: this format may exceed ISO 8601 limit of milliseconds (3 decimal places).

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

Example code

示例代码

Here is some example code in Java 8 Update 51.

这是 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

输出:2015-08-20T08:26:21Z

Changing to a fractional second, .08

更改为小数秒, .08

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

output: 2015-08-20T08:26:21.080Z

输出:2015-08-20T08:26:21.080Z

If interested in any time zone other than UTC, then make a ZonedDateTimeobject from that Instant.

如果对 UTC 以外的任何时区感兴趣,那么ZonedDateTime从那个Instant.

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

回答by karim mohsen

Your format is just not right try this :-

你的格式不正确试试这个:-

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();
    }

回答by Emily Mabrey

Conversion of a date Stringof unknown formatting into a date Stringthat uses known formatting can be accomplished using two DateFormatobjects- one dynamically configured to parse the format of the input String, and one configured to generate the formatted output String. For your situation the input Stringformatting is unspecified and must be provided by the caller, however, the output Stringformatting can be configured to use ISO 8601 formatting without additional input. Essentially, generating an ISO 8601 formatted date Stringoutput requires two inputs provided by the caller- a Stringcontaining the formatted date and another Stringthat contains the SimpleDateFormatformat.

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

Here is the described conversion as Java code (I deliberately have left out null checks and validations, add these as appropriate for your code):

这是作为 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);
}

If you want to modify that method please note that SimpleDateFormatis not thread-safe, and that you should not use it from a static context without a workaround for multi-threaded code (ThreadLocalis commonly used to do just such a workaround for SimpleDateFormat).

如果您想修改该方法,请注意它SimpleDateFormat不是线程安全的,并且您不应在没有多线程代码变通方法的情况下从静态上下文中使用它(ThreadLocal通常用于为 做这样的变通方法SimpleDateFormat)。

An additional "gotcha" is the use of a Localeduring the construction of the SimpleDateFormatobjects- do not remove the Localeconfiguration. It is not safe to allow the system to choose to use the default Localebecause that is user/machine specific. If you do allow it to use the default Locale, you run the risk of transient bugs because your development machine uses a Localedifferent than the Localeof your end-user. You do not have to use my selected ENGLISH Locale, it is perfectly fine to use a different Locale (you should understand the rules of that Localeand modify the code as appropriate however). Specification of no Localeand utilization of the system default is incorrect however, and likely will lead to many frustrating hours trying to diagnose an elusive bug.

一个额外的“陷阱”是Locale在构建对象期间使用 a SimpleDateFormat- 不要删除Locale配置。允许系统选择使用默认值是不安全的,Locale因为这是特定于用户/机器的。如果您确实允许它使用默认Locale,则您将面临暂时性错误的风险,因为您的开发机器使用LocaleLocale与您的最终用户不同。您不必使用我选择的 ENGLISH Locale,使用不同的 Locale 完全没问题(您应该了解其中的规则Locale并根据需要修改代码)。Locale然而,系统默认值的 no和利用率的规范是不正确的,并且可能会导致许多令人沮丧的时间试图诊断一个难以捉摸的错误。

Please understand this solution is not ideal as of Java 8 and the inclusion of the JodaTime based classes, like Instant. I chose to answer using the outdated API's because those were what you seemed concerned with in your question. If you are using Java 8 I strongly urge to learn and utilize the new classes as they are an improvement in almost every conceivable way.

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