ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

我想我应该使用 SimpleDateFormat 进行解析,但我必须先知道格式字符串。到目前为止,我所拥有的只是 yyyy-MM-dd,因为我不知道此字符串中的 T 是什么意思——与时区有关吗?此日期字符串来自 Files CMIS download history media type 上显示的 lcmis:downloadedOn 标记。

这是ISO 8601
@TomaszNurkiewicz,不是。 ISO8601最后没有Z。
ISO8601 确实允许 Z 结尾。请参阅上面的链接,查找 UTC。
@t1gor 末尾的 ZZulu 的缩写,表示 UTC。这种格式肯定标准日期时间文本格式ISO 8601集合的一部分。顺便说一句,这些标准格式在 java.time 类中默认使用。
仅供参考,麻烦的旧日期时间类(例如 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat)现在是 legacy,被 Java 8 中内置的 java.time 类所取代。 Java 9。见 Tutorial by Oracle

J
Jesús Barrera

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


为什么我们需要在 TZ 周围加上单引号?
@MarounMaroun:基本上我们想要那些 literal 字符。 T 可能没有必要(我不记得 SimpleDateFormat 如何处理未知说明符),但对于 Z,我们希望它是字符“Z”而不是“UTC 偏移值”(例如“00”) .
@nyedidikeke:在您链接到的维基百科页面中,它显示 UTC 的“祖鲁时区”。我不确定你认为你在纠正什么。
@JonSkeet:它可能会引起不必要的辩论;不是对您的回答提出异议,而是为了引起人们对 Z 的注意,它的字母首字母来自“零 UTC 偏移”。字母 Z 在北约拼音字母表中被称为“祖鲁”。反过来,引用零 UTC 偏移量的军事方法锚定在字母 Z 上,他们将其识别为 Zulu,从而获得了他们的代号:Zulu time zone。重要的是要注意 Z 并没有失去它的意义,仍然是零 UTC 偏移量的区域指示符,因为祖鲁时区(来自 Z)只是一种继承的编码语言来引用它。
@nyedidikeke:我仍然不同意其他人是否会在参考我的答案时关心区别,但我已经更新了它。不过,我不会详细介绍所有细节,因为历史与答案大致无关。
B
Basil Bourque

tl;博士

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

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

ISO 8601

此格式由合理的实用标准 ISO 8601 定义。

T 将日期部分与时间部分分开。末尾的 Z 表示 UTC(即与 UTC 的偏移量为零时分秒)。 Zpronounced “Zulu”

java.time

与 Java 的最早版本捆绑在一起的旧日期时间类已被证明设计不佳、混乱且麻烦。避开他们。

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

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

Instant 类表示 UTC 中时间轴上的一个时刻,分辨率为 nanoseconds。该类可以直接解析您的输入字符串,而无需定义格式模式。

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

https://i.stack.imgur.com/p0TgD.png

关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendar 和 & SimpleDateFormat

要了解更多信息,请参阅 Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

Joda-Time 项目现在位于 maintenance mode 中,建议迁移到 java.time 类。

您可以直接与您的数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC driver。不需要字符串,不需要 java.sql.* 类。休眠 5 和JPA 2.2 支持 java.time

从哪里获得 java.time 类?

Java SE 8、Java SE 9、Java SE 10、Java SE 11 及更高版本 - 标准 Java API 的一部分,具有捆绑的实现。 Java 9 带来了一些小功能和修复。

Java 9 带来了一些小功能和修复。

Java SE 6 和 Java SE 7 大多数 java.time 功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7。

大多数 java.time 功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7。

Android 更高版本的 Android (26+) 捆绑了 java.time 类的实现。对于早期的 Android (<26),称为 API 脱糖的过程带来了最初未内置于 Android 中的 java.time 功能的子集。如果脱糖不能提供您所需要的,ThreeTenABP 项目会将 ThreeTen-Backport(上面提到的)适配到 Android。请参阅如何使用 ThreeTenABP……。

更高版本的 Android (26+) 捆绑了 java.time 类的实现。

对于早期的 Android (<26),称为 API 脱糖的过程带来了最初未内置于 Android 中的 java.time 功能的子集。如果脱糖不能提供您所需要的,ThreeTenABP 项目会将 ThreeTen-Backport(上面提到的)适配到 Android。请参阅如何使用 ThreeTenABP……。

如果脱糖不能提供您所需要的,ThreeTenABP 项目会将 ThreeTen-Backport(上面提到的)适配到 Android。请参阅如何使用 ThreeTenABP……。

https://i.stack.imgur.com/Sksw9.png


@star “祖鲁”来自军事和航空传统,其中 25 个字母 AZ(没有“J”),每个字母都有一个可发音的名称,代表 their version of time zones。 “祖鲁”区域与 UTC 的时差为零。请参阅 thisthis
LocalDateTime.parse("2021-11-22T09:00:00.000Z") 解析时抛出异常。有什么建议,如何使用 java.time 格式化相同的输入以格式化为“EEEE,MMMM dd”?谢谢。
@Faisal您尝试将时刻(带有时间和偏移的日期)解析为 LocalDateTime 是不合逻辑的。 LocalDateTime 不是时刻,也不是时间线上的特定点,因为它没有与 UTC 或时区偏移的概念。您的输入应被解析为 Instant,如下所示:Instant.parse("2021-11-22T09:00:00.000Z")
说得通。可以将实例解析为预期格式吗?
@Faisal 应用您希望通过其感知日期的时区 (ZoneId)。这会给你一个ZonedDateTime。从中提取一个LocalDate。使用 DateTimeFormatter 以您想要的任何格式生成文本,或自动本地化。所有这些都已经在 Stack Overflow 上介绍过很多次了。
s
smparkes

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


这也是“2016-01-27T17:44:55UTC”,ISO8601 吗?
我不相信。它很接近,但不允许使用 UTC 作为后缀。它必须是 Z 或时区偏移量,例如 +0100。但是,Z 和 UTC 具有相同的含义,因此将 UTC 更改为 Z 将产生有效的 ISO 8601。
V
VeryLazyBoy

除了第一个答案,还有其他方法可以解析它。解析它:

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

A
Arvind Kumar Avinash

java.time

您不需要 DateTimeFormatter 来解析给定的日期时间字符串。

Java SE 8 日期时间 API(java.time API 或现代日期时间 API)基于 ISO 8601,只要日期时间字符串符合 ISO 8601,就不需要显式使用 DateTimeFormatter 对象标准。

字符串中的 Z 是零时区偏移量的 timezone designator。它代表 Zulu 并指定 Etc/UTC 时区(时区偏移量为 +00:00 小时)。

根据 ISO-8601 标准,字符串中的 T 只是 Date-Time separator

演示:

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2011-08-12T20:17:46.384Z";

        Instant instant = Instant.parse(strDateTime);
        OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime);
        
        System.out.println(instant);
        System.out.println(odt);
        System.out.println(zdt);
    }
}

输出:

2011-08-12T20:17:46.384Z
2011-08-12T20:17:46.384Z
2011-08-12T20:17:46.384Z

详细了解 java.time,即来自 Trail: Date Timemodern Date-Time API*

旧的日期时间 API

旧的日期时间 API(java.util 日期时间 API 及其格式化 API,SimpleDateFormat)已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*

为了完整起见,我编写了一个解决方案来使用遗留 API 解析这个日期时间字符串。

不要在带有日期时间解析/格式化 API 的模式中使用 'Z'

如上所述,Z(不带引号)是零时区偏移的时区指示符,而 'Z' 只是一个字符文字,它没有任何意义。使用格式,y-M-d'T'H:m:s.SSSXXX。检查 documentation 以了解有关这些符号的更多信息。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        String strDateTime = "2011-08-12T20:17:46.384Z";

        SimpleDateFormat sdf = new SimpleDateFormat("y-M-d'T'H:m:s.SSSXXX", Locale.ENGLISH);
        Date date = sdf.parse(strDateTime);
        // ...
    }
}

请注意,java.util.Date 对象不像 modern Date-Time types 那样是真正的日期时间对象;相反,它表示自称为“纪元”的标准基准时间以来的毫秒数,即 January 1, 1970, 00:00:00 GMT(或 UTC)。由于它不保存任何格式和时区信息,它应用格式、EEE MMM dd HH:mm:ss z yyyy 和 JVM 的时区来返回从该毫秒值派生的 Date#toString 值。如果您需要以不同的格式和时区打印日期时间,则需要使用具有所需格式和适用时区的 SimpleDateFormat,例如

sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String formatted = sdf.format(date);
System.out.println(formatted); // 2011-8-12T20:17:46.384Z

Joda 日期时间 API

下面引用的是 Home Page of Joda-Time 处的通知:

请注意,从 Java SE 8 开始,用户被要求迁移到 java.time (JSR-310) - JDK 的核心部分,它取代了这个项目。

同样,为了完整起见,我编写了一个解决方案来使用 Joda Date-Time API 解析这个 Date-Time 字符串。

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

public class Main {
    public static void main(String[] args) {
        String dateTimeStr = "2011-08-12T20:17:46.384Z";
        DateTimeFormatter dtf = DateTimeFormat.forPattern("y-M-d'T'H:m:s.SSSZ").withOffsetParsed();
        DateTime dateTime = dtf.parseDateTime(dateTimeStr);
        System.out.println(dateTime);
    }
}

输出:

2011-08-12T20:17:46.384Z

* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project


r
rahulrvp

如果你们正在寻找适用于 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


M
Mayank PATEl

Z 代表 UTC 时区。使用 java8+,您可以简单地使用 Instant。

    public static void main(String[] args) {
    String time = "2022-06-08T04:55:01.000Z";
    System.out.println(Instant.parse(time).toEpochMilli());
}

F
Firma 777

在 JavaScript 中

let isoDateTimeString = new Date().toISOString();

描述

日期/时间格式(如“YYYY-MM-DDThh:mm:ss.SSSZ”)是 ISO 8601 日期/时间格式。


S
Salih Kesepara

您可以使用以下示例。

    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,偏移量为零。您的格式正在丢弃这个重要的事实。此外,甚至无需费心定义此格式模式。内置了此模式的格式化程序。
G
Gapmeister66

这种技术将 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,但这并不总是简单、有效或必要的。
s
spencemw

@John-Skeet 给了我解决这个问题的线索。作为一个年轻的程序员,这个小问题很容易被忽略,也很难诊断。所以我分享它,希望它对某人有所帮助。

我的问题是我想从我无法影响的 JSON 中解析以下包含时间戳的字符串,并将其放入更有用的变量中。但我不断收到错误。

所以给定如下(注意ofPattern()里面的字符串参数;

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

问题? Pattern 末尾的 Z 需要像 'T' 一样包裹在 'Z' 中。将 "yyyyMMdd'T'HHmmss.SSSZ" 更改为 "yyyyMMdd'T'HHmmss.SSS'Z'" 即可。

从模式中移除 Z 也会导致错误。

坦率地说,我希望 Java 类能够预料到这一点。


这已被问及回答 herehere。你的解决方案是错误的。虽然 T 是一个文字并且需要被引用,但 Z 是一个偏移量(零)并且需要被解析,否则你会得到错误的结果。我不知道你的意思是它没有被预料到,我相信它有。
不,不,不,不要忽略 Z。您正在丢弃有价值的信息。在忽略时区或从 UTC 偏移的情况下处理日期时间值就像在忽略货币的情况下处理一笔钱!
T 只是将日期部分与时间部分分开,并没有添加任何意义。另一方面,Z 肯定增加了意义。
奥莱,谢谢你的链接。我肯定会读那些。我承认我作为一个年轻人肯定是错的。我要说的是,将 Z 像模式中的字符一样用单引号括起来解决了错误。我的批评是,无论是谁设计了课程的“模式”部分,都可以围绕“Z”(或不同时区?)的存在与否以及“T”是否包含在“”中进行编码。因为他们不是独一无二的。我处理的格式来自从商业 API 解析为字符串的 JSON。但我需要将所有这些解析为日期时间日历等,以使它们更有用。