我有以下日期: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
标记。
java.util.Date
、java.util.Calendar
和 java.text.SimpleDateFormat
)现在是 legacy,被 Java 8 中内置的 java.time 类所取代。 Java 9。见 Tutorial by Oracle。
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()
。
tl;博士
您的输入字符串使用标准 ISO 8601 格式。
Instant.parse ( "2011-08-12T20:17:46.384Z" )
ISO 8601
此格式由合理的实用标准 ISO 8601 定义。
T
将日期部分与时间部分分开。末尾的 Z
表示 UTC(即与 UTC 的偏移量为零时分秒)。 Z
是 pronounced “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.Date
、Calendar
和 & 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
java.time
格式化相同的输入以格式化为“EEEE,MMMM dd”?谢谢。
LocalDateTime
是不合逻辑的。 LocalDateTime
不是时刻,也不是时间线上的特定点,因为它没有与 UTC 或时区偏移的概念。您的输入应被解析为 Instant
,如下所示:Instant.parse("2021-11-22T09:00:00.000Z")
。
ZoneId
)。这会给你一个ZonedDateTime
。从中提取一个LocalDate
。使用 DateTimeFormatter
以您想要的任何格式生成文本,或自动本地化。所有这些都已经在 Stack Overflow 上介绍过很多次了。
不确定 Java 解析,但那是 ISO8601:http://en.wikipedia.org/wiki/ISO_8601
除了第一个答案,还有其他方法可以解析它。解析它:
(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");
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 Time 的 modern 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 desugaring 和 How to use ThreeTenABP in Android Project。
如果你们正在寻找适用于 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
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());
}
在 JavaScript 中
let isoDateTimeString = new Date().toISOString();
描述
日期/时间格式(如“YYYY-MM-DDThh:mm:ss.SSSZ”)是 ISO 8601 日期/时间格式。
您可以使用以下示例。
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,偏移量为零。您的格式正在丢弃这个重要的事实。此外,甚至无需费心定义此格式模式。内置了此模式的格式化程序。
这种技术将 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.Date
和 Joda-Time 项目几年前都被 JSR 310 中定义的现代 java.time 类所取代。这里的建议早已过时。
@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 类能够预料到这一点。
T
是一个文字并且需要被引用,但 Z
是一个偏移量(零)并且需要被解析,否则你会得到错误的结果。我不知道你的意思是它没有被预料到,我相信它有。
Z
。您正在丢弃有价值的信息。在忽略时区或从 UTC 偏移的情况下处理日期时间值就像在忽略货币的情况下处理一笔钱!
T
只是将日期部分与时间部分分开,并没有添加任何意义。另一方面,Z
肯定增加了意义。
T
和Z
周围加上单引号?T
可能没有必要(我不记得 SimpleDateFormat 如何处理未知说明符),但对于Z
,我们希望它是字符“Z”而不是“UTC 偏移值”(例如“00”) .