这个日期格式是什么?2011-08-12T20:17:46.384Z


381

我有以下日期: 2011-08-12T20:17:46.384Z。这是什么格式?我正在尝试通过Java 1.4解析它,DateFormat.getDateInstance().parse(dateStr)并且

java.text.ParseException:无法解析的日期:“ 2011-08-12T20:17:46.384Z”

我认为我应该使用SimpleDateFormat进行解析,但是我必须首先知道格式字符串。到目前为止yyyy-MM-dd,我所拥有的只是,因为我不知道T该字符串的含义是什么-与时区有关?此日期字符串来自“ 文件CMIS下载历史记录”媒体类型lcmis:downloadedOn上显示的标签。



3
@TomaszNurkiewicz,不是。ISO8601的末尾没有Z。
t1gor

4
ISO8601允许在末尾加上Z。请参阅上面的链接,查找UTC。
乔纳森·罗森

2
@ t1gor Z结尾处的缩写Zulu,表示UTC。这种格式无疑ISO 8601标准日期时间文本格式集合的一部分。顺便说一下,这些标准格式默认在java.time类中使用。
罗勒·布尔克

3
仅供参考,麻烦的旧日期,时间类,如java.util.Datejava.util.Calendarjava.text.SimpleDateFormat现在的遗产,由取代java.time内置到Java 8的Java 9.请参见类由Oracle教程
罗勒·布尔克

Answers:


511

T只是将日期和时间分开的文字,Z表示“零时偏移”,也称为“祖鲁时间”(UTC)。如果您的字符串始终带有“ Z”,则可以使用:

SimpleDateFormat format = new SimpleDateFormat(
    "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));

或使用Joda Time,您可以使用ISODateTimeFormat.dateTime()


7
为什么我们需要在T和周围加上单引号Z
Maroun 2015年

7
@MarounMaroun:基本上我们想要那些文字字符。可能不是必需的T(我不记得SimpleDateFormat如何处理未知的说明符),但是对于Z我们希望它是字符“ Z”而不是“ UTC偏移值”(例如“ 00”)。
乔恩·斯基特

2
@nyedidikeke:在链接到的Wikipedia页面上,它显示UTC的“祖鲁时区”。我不确定您认为自己要纠正什么。
乔恩·斯基特

9
@JonSkeet:这可能会引起不必要的辩论;不反对您的答案,而是要引起注意的Z是从“零UTC偏移”开始的字母。在北约语音字母中,字母Z被称为“祖鲁语” 。反过来,引用零UTC偏移量的军事方法被固定在字母Z上,他们将其标识为Zulu,并为其获得了代号:Zulu时区。重要的是要注意,Z并没有失去其含义,仍然是UTC零偏移的区域指示符,因为Zulu时区(来自Z)只是引用它的继承编码语言。
nyedidikeke '16

2
@nyedidikeke:关于我的回答,我仍然不同意是否有人会关心这个区别,但是我已经对其进行了更新。不过,由于历史与答案基本无关,因此我不会详细介绍所有细节。
乔恩·斯基特

86

tl; dr

输入字符串使用标准ISO 8601格式。

Instant.parse ( "2011-08-12T20:17:46.384Z" ) 

ISO 8601

此格式由明智的实用标准ISO 8601定义

T日期部分与时间部分分开。该Z对端装置UTC(即,偏移从-UTC零小时-分钟-秒)。将Z明显的“祖鲁”

java.time

事实证明,与最早的Java版本捆绑在一起的旧的日期时间类设计不良,令人困惑且麻烦。避免他们。

相反,请使用Java 8及更高版本中内置的java.time框架。java.time类取代了旧的日期时间类和非常成功的Joda-Time库。

解析/生成日期时间值的文本表示时,java.time类默认使用ISO 8601

Instant级表示时间轴上的时刻UTC,分辨率为纳秒。该类可以直接解析您的输入字符串,而无需费心定义格式设置模式。

Instant instant = Instant.parse ( "2011-08-12T20:17:46.384Z" ) ;

Java中的日期时间类型表(现代和旧式)


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar,和SimpleDateFormat

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

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

在哪里获取java.time类?

与哪个版本的Java或Android一起使用的哪个java.time库的表

ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多


3
@star“祖鲁语”来自军事和航空传统,其中25个字母AZ(无“ J”)字母(每个字母具有明显的名称)代表其时区版本。“祖鲁人”区域与UTC的时差为零小时。看到这个这个
罗勒·布尔克

27

不确定Java解析,但这是ISO8601:http : //en.wikipedia.org/wiki/ISO_8601


这也是ISO8601的“ 2016-01-27T17:44:55UTC”吗?
user1997292

我不相信 已经结束,但是不允许使用UTC作为后缀。它必须是Z或时区偏移量,例如+0100。Z和UTC具有相同的含义,虽然如此,改变UTCž会产生有效的ISO 8601
smparkes

9

还有其他解析方法,而不是第一个答案。要对其进行解析,请执行以下操作:

(1)如果要获取有关日期和时间的信息,可以将其解析为ZonedDatetime(自Java 8以来)或Date(旧)对象:

// ZonedDateTime's default format requires a zone ID(like [Australia/Sydney]) in the end.
// Here, we provide a format which can parse the string correctly.
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2011-08-12T20:17:46.384Z", dtf);

要么

// 'T' is a literal.
// 'X' is ISO Zone Offset[like +01, -08]; For UTC, it is interpreted as 'Z'(Zero) literal.
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX";

// since no built-in format, we provides pattern directly.
DateFormat df = new SimpleDateFormat(pattern);

Date myDate = df.parse("2011-08-12T20:17:46.384Z");

(2)如果您不在乎日期和时间,而只想将信息视为纳秒级的时间,则可以使用Instant

// The ISO format without zone ID is Instant's default.
// There is no need to pass any format.
Instant ins = Instant.parse("2011-08-12T20:17:46.384Z");

1

如果您正在寻找适用于Android的解决方案,则可以使用以下代码从时间戳字符串获取新纪元。

public static long timestampToEpochSeconds(String srcTimestamp) {
    long epoch = 0;

    try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            Instant instant = Instant.parse(srcTimestamp);
            epoch = instant.getEpochSecond();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'", Locale.getDefault());
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
            Date date = sdf.parse(srcTimestamp);
            if (date != null) {
                epoch = date.getTime() / 1000;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return epoch;
}

输入范例:2019-10-15T05:51:31.537979Z

样本输出:1571128673


0

您可以使用以下示例。

    String date = "2011-08-12T20:17:46.384Z";

    String inputPattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    String outputPattern = "yyyy-MM-dd HH:mm:ss";

    LocalDateTime inputDate = null;
    String outputDate = null;


    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputPattern, Locale.ENGLISH);
    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputPattern, Locale.ENGLISH);

    inputDate = LocalDateTime.parse(date, inputFormatter);
    outputDate = outputFormatter.format(inputDate);

    System.out.println("inputDate: " + inputDate);
    System.out.println("outputDate: " + outputDate);

您不应该在前后加上撇号Z。那意味着期待但忽略那封信。但是那封信不容忽视。该字母提供了有价值的信息,即该字符串应用于UTC,偏移量为零。您的格式正在舍弃这一重要事实。此外,甚至不必费心定义此格式化模式。针对此模式格式是内置的。
罗勒布尔克

-1

此技术将java.util.Date转换为UTC格式(或任何其他格式),然后再次返回。

像这样定义一个类:

import java.util.Date;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class UtcUtility {

public static DateTimeFormatter UTC = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZoneUTC();


public static Date parse(DateTimeFormatter dateTimeFormatter, String date) {
    return dateTimeFormatter.parseDateTime(date).toDate();
}

public static String format(DateTimeFormatter dateTimeFormatter, Date date) {
    return format(dateTimeFormatter, date.getTime());
}

private static String format(DateTimeFormatter dateTimeFormatter, long timeInMillis) {
    DateTime dateTime = new DateTime(timeInMillis);
    String formattedString = dateTimeFormatter.print(dateTime);
    return formattedString;
}

}

然后像这样使用它:

Date date = format(UTC, "2020-04-19T00:30:07.000Z")

要么

String date = parse(UTC, new Date())

如果需要,您还可以定义其他日期格式(不仅限于UTC)


这两个项目java.util.DateJoda-Time项目都在多年前被JSR 310中定义的现代java.time类所取代。这里的建议早已过时。
罗勒·布尔克

java.time是Java 8中引入的。此问题专门引用Java 1.4,因此,我特意避免使用较新的类。该解决方案适合较旧的代码库。我想作者可以将其代码库移至Java 8,但这并不总是那么简单,高效或必要。
Gapmeister66

-1

@ John-Skeet为我提供了解决此问题的线索。作为一个年轻的程序员,这个小问题很容易遗漏并且很难诊断。因此,我希望分享它,希望对您有所帮助。

我的问题是,我想解析以下字符串,将其与来自我没有影响的JSON的时间戳进行对比,并将其放入更有用的变量中。但是我不断出错。

因此,给出以下内容(注意Pattern()内的字符串参数;

String str = "20190927T182730.000Z"

LocalDateTime fin;
fin = LocalDateTime.parse( str, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSZ") );

错误:

Exception in thread "main" java.time.format.DateTimeParseException: Text 
'20190927T182730.000Z' could not be parsed at index 19

问题?模式“末尾的Z”需要像“ T”一样包裹在“ Z”中。更改 "yyyyMMdd'T'HHmmss.SSSZ""yyyyMMdd'T'HHmmss.SSS'Z'",即可使用。

从样式中完全删除Z也会导致错误。

坦白地说,我希望Java类已经预见到这一点。


1
这已经在这里这里被要求和回答。而且您的解决方案是错误的。虽然T是字面值且需要用引号引起来,但它Z是一个偏移量(零),需要这样解析,否则您将得到错误的结果。我不知道您的意思是意料之外的,我相信它是意料之中的。
Ole VV

1
不,不,不,不要忽略Z。您正在丢弃有价值的信息。在忽略时区或UTC偏移的情况下处理日期时间值就像在忽略货币时处理金额一样!
罗勒·布尔克

1
T仅仅分离时间的日部分日期部分,并增加了没有意义。在Z另一方面肯定更有意义。
罗勒·布尔克

好,谢谢您的链接。我一定会读这些书。而且我接受我年轻时肯定是错误的。我只是在说Z像模式中的char一样用单引号引起来解决了错误。我的批评是,设计班级“模式”部分的任何人都可能围绕“ Z”(或差异时区?)的存在或不存在以及是否将“ T”包裹在“”中进行编码。因为他们没有它的独特性。Im处理的格式来自将商业API解析为字符串的JSON。但我需要将所有内容解析为日期时间日历等,以使其更加有用。
spencemw19年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.