187

我有 SimpleDateFormat 构造函数

SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")

我正在解析字符串"2013-09-29T18:46:19Z".

我读过这里 Z 代表GMT/UTC时区。但是当我在控制台上打印这个日期时,它会为返回的日期打印 IST timezne。

现在我的问题是我的输出是对还是错?

4

8 回答 8

296

您尚未设置时区,仅Z在日期/时间的末尾添加了 a,因此它看起来像 GMT 日期/时间,但这不会更改值。

将时区设置为 GMT,它将是正确的。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
于 2013-10-01T11:41:56.097 回答
113

'T'并且'Z'在这里被视为常数。您需要在Z没有引号的情况下通过。此外,您需要在输入字符串中指定时区。

示例:2013-09-29T18:46:19-0700 格式为"yyyy-MM-dd'T'HH:mm:ssZ"

于 2013-10-01T09:23:14.627 回答
58

从 ISO 8601 字符串到 Java 日期对象

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.parse("2013-09-29T18:46:19Z"); //prints-> Mon Sep 30 02:46:19 CST 2013

如果你不设置TimeZone.getTimeZone("GMT")那么它会输出Sun Sep 29 18:46:19 CST 2013

从 Java 日期对象到 ISO 8601 字符串

并将对象转换Date为 ISO 8601 标准 ( yyyy-MM-dd'T'HH:mm:ss'Z') 使用以下代码

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));           
System.out.println(sdf.format(new Date())); //-prints-> 2015-01-22T03:23:26Z

另请注意,没有' '在 Zyyyy-MM-dd'T'HH:mm:ssZ打印2015-01-22T03:41:02+0000

于 2015-01-22T03:29:30.413 回答
49

如果您想处理 Date 的“标准”JSON 表示,那么最好使用此模式:"yyyy-MM-dd'T'HH:mm:ssX".

注意X最后。 它将处理 ISO 8601 标准中的时区,而 ISO 8601 正是在 Javascript 中产生此语句的原因new Date().toJSON()

与其他答案相比,它有一些好处:

  1. 您不需要要求您的客户在 GMT 中发送日期
  2. 您无需使用以下方法将 Date 对象显式转换为 GMT:sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
于 2015-04-07T22:12:06.440 回答
35

tl;博士

从 Java 8 开始,其他答案已过时。

Instant                           // Represent a moment in UTC. 
.parse( "2013-09-29T18:46:19Z" )  // Parse text in standard ISO 8601 format where the `Z` means UTC, pronounces “Zulu”.
.atZone(                          // Adjust from UTC to a time zone. 
    ZoneId.of( "Asia/Kolkata" )
)                                 // Returns a `ZonedDateTime` object. 

ISO 8601

您的字符串格式恰好符​​合ISO 8601标准。该标准定义了将各种日期时间值表示为文本的合理格式。

java.time

旧的java.util.Date/.Calendarjava.text.SimpleDateFormat类已被 Java 8 及更高版本中内置的 java.time 框架所取代。请参阅教程避免使用旧类,因为它们已被证明设计不佳、令人困惑且麻烦。

旧类中的部分糟糕设计让您感到厌烦,该toString方法在生成实际为 UTC (GMT) 的日期时间值的文本表示时应用了 JVM 的当前默认时区;善意但令人困惑。

java.time 类在解析/生成日期时间值的文本表示时默认使用 ISO 8601 格式。所以不需要指定解析模式。

An是UTCInstant时间线上的时刻。

Instant instant = Instant.parse( "2013-09-29T18:46:19Z" );

您可以根据需要应用时区来生成ZonedDateTime对象。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );

Java 中的日期时间类型表,包括现代和传统

于 2016-03-09T07:05:21.790 回答
28

如果您没有继续使用 java8 的选项,最好使用 'yyyy-MM-dd'T'HH:mm:ssX XX ',因为它会再次正确解析(虽然只有一个 X,但情况可能并非如此。 ..取决于您的解析功能)

X 生成:+01

XXX 生成:+01:00

于 2017-02-15T15:20:42.340 回答
5

'Z'不一样Z

'Z'只是一个字符文字,而是零时区偏移Z时区指示符。它代表 Zulu 并指定Etc/UTC时区(时区偏移量为+00:00小时)。

因此,请勿使用'Z'in 模式进行解析/格式化。

,java.time现代日期时间 API

现代日期时间 API 基于ISO 8601DateTimeFormatter ,只要日期时间字符串符合 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

An代表UTCInstant时间线上的一个瞬时点。输出中的 是零时区偏移的时区指示符。它代表 Zulu 并指定时区(时区偏移量为小时)。ZEtc/UTC+00:00

注意#1:如果您需要找出Instant特定时区中的日期和时间,您可以使用Instant#atZone例如以下代码将Instant在印度打印日期和时间:

ZonedDateTime zdtIndia = instant.atZone(ZoneId.of("Asia/Kolkata"));
System.out.println(zdtIndia);

您甚至可以使用例如以下代码将对象ZonedDateTime从一个时区转换为另一个时区将转换为表示印度日期和时间的对象:ZonedDateTime#withZoneSameInstantzdtZonedDateTime

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了解有关现代日期时间 API *的更多信息。

为什么您的java.util.Date对象打印印度日期和时间?

java.util.Date对象仅表示自称为“纪元”的标准基准时间(即 1970 年 1 月 1 日 00:00:00 GMT(或 UTC)以来的毫秒数)。由于它不保存任何时区信息,因此它的函数应用 JVM 的时区以从该毫秒值派生的格式toString返回 a 。要以不同的格式和时区表示对象,您需要使用所需的格式和适用的时区,例如StringEEE MMM dd HH:mm:ss zzz yyyyStringjava.util.DateSimpleDateFormat

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 工作level 仍然不符合 Java-8,请检查Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

于 2021-06-12T21:16:53.940 回答
1

对于 Java 8: 您可以使用 inbuiltjava.time.format.DateTimeFormatter来减少任何拼写错误的机会,例如

DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;

ISO_ZONED_DATE_TIME 表示2011-12-03T10:15:30+01:00[Europe/Paris]是 Oracle 提供的捆绑标准 DateTime 格式之一链接

于 2020-05-08T10:51:45.160 回答