'Z' 与 Z 不一样
'Z' 只是一个字符文字,而Z 是零时区偏移量的timezone designator。它代表 Zulu 并指定 Etc/UTC 时区(其时区偏移量为 +00:00 小时)。
因此,不要在模式中使用 'Z' 进行解析/格式化。
java.time,现代日期时间 API
现代日期时间 API 基于 ISO 8601 并且不需要明确使用 DateTimeFormatter 对象,只要日期时间字符串符合 ISO 8601 标准。日期时间字符串 2013-09-29T18:46:19Z 符合 ISO 8601 标准。
演示:
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
Instant instant = Instant.parse("2013-09-29T18:46:19Z");
OffsetDateTime odt = OffsetDateTime.parse("2013-09-29T18:46:19Z");
ZonedDateTime zdt = ZonedDateTime.parse("2013-09-29T18:46:19Z");
System.out.println(instant);
System.out.println(odt);
System.out.println(zdt);
}
}
输出:
2013-09-29T18:46:19Z
2013-09-29T18:46:19Z
2013-09-29T18:46:19Z
ONLINE DEMO
Instant 表示UTC 中时间轴上的一个瞬时点。输出中的 Z 是零时区偏移量的 timezone designator。它代表 Zulu 并指定 Etc/UTC 时区(时区偏移量为 +00:00 小时)。
注意#1:如果您需要找出Instant 在特定时区中代表的日期和时间,您可以使用Instant#atZone,例如以下代码将在印度打印此Instant 的日期和时间:
ZonedDateTime zdtIndia = instant.atZone(ZoneId.of("Asia/Kolkata"));
System.out.println(zdtIndia);
您甚至可以使用ZonedDateTime#withZoneSameInstant 将ZonedDateTime 的对象从一个时区转换为另一个时区,例如以下代码会将zdt 转换为ZonedDateTime 的对象,表示印度的日期和时间:
ZonedDateTime zdtIndia = zdt.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
System.out.println(zdtIndia);
注意#2:出于任何原因,如果您需要将此Instant 的对象转换为java.util.Date 的对象,您可以这样做:
Date date = Date.from(instant);
您甚至可以将OffsetDateTime和ZonedDateTime的对象转换为java.util.Date的对象,如下所示:
Date date = Date.from(odt.toInstant());
&
Date date = Date.from(zdt.toInstant());
通过 Trail: Date Time 了解有关 modern Date-Time API* 的更多信息。
为什么你的java.util.Date 对象打印了印度的日期和时间?
java.util.Date 对象仅表示自称为“纪元”的标准基准时间(即 1970 年 1 月 1 日 00:00)以来的毫秒数: 00 GMT(或 UTC)。由于它不保存任何时区信息,它的toString 函数应用JVM 的时区以EEE MMM dd HH:mm:ss zzz yyyy 的格式返回一个String,该格式派生自此毫秒价值。要以不同的格式和时区获取java.util.Date 对象的String 表示,您需要使用具有所需格式和适用时区的SimpleDateFormat,例如
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
String strDate = sdf.format(date);
System.out.println(strDate);
演示:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH);
Date date = sdf.parse("2013-09-29T18:46:19Z");
// In JVM's timezone and default format as returned by Date#toString
System.out.println(date);
// In UTC and custom format
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDate = sdf.format(date);
System.out.println(strDate);
// In India and custom format
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
strDate = sdf.format(date);
System.out.println(strDate);
}
}
输出(我的时区是欧洲/伦敦):
Sun Sep 29 19:46:19 BST 2013
2013-09-29T18:46:19Z
2013-09-30T00:16:19+05:30
ONLINE DEMO
* 出于任何原因,如果您必须坚持使用 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。