Java SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") 给出的时区为 IST

SimpleDateFormat 对应的构造函数为:

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

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

这里的 Z 代表 GMT/UTC 时区。但是当我在控制台打印这个日期时,返回的日期打印出来的是 IST 时区。

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

768830 次浏览

'T''Z'在这里被认为是常量。你需要传递不带引号的Z。此外,您需要在输入字符串中指定时区。

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

你没有设置时区,只是在日期/时间的末尾添加了Z,所以它看起来像一个GMT日期/时间,但这不会改变值。

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

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

从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字符串

要将Dateobject转换为ISO 8601 Standard (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

还要注意,在Z处没有' 'yyyy-MM-dd'T'HH:mm:ssZ将打印2015-01-22T03:41:02+0000

如果你想处理日期的'标准' JSON表示,那么最好使用这个模式:"yyyy-MM-dd'T'HH:mm:ssX"

注意结尾的X它将处理ISO 8601标准的时区和ISO 8601正是在Javascript new Date().toJSON()中生成这个语句的

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

  1. 您不需要要求您的客户端以GMT发送日期
  2. 你不需要使用sdf.setTimeZone(TimeZone.getTimeZone("GMT"));显式地将Date对象转换为GMT

博士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。在Java 8及以后版本中内置了时间框架。看到教程避免使用旧的类,因为他们已被证明是糟糕的设计,混乱,和麻烦。

旧类中的部分糟糕设计已经困扰了你,其中toString方法在生成实际为UTC (GMT)的日期-时间值的文本表示时应用JVM的当前默认时区;善意但令人困惑。

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

InstantUTC中时间轴上的一个时刻。

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

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

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

现代和传统Java日期-时间类型表

和如果你没有选择去java8更好的使用 'yyyy-MM-dd' t ' hh:mm:ssXXX',因为它再次被正确解析(而只有一个X可能不是这种情况……取决于你的解析函数)

X生成:+01

XXX生成:+01:00

For Java 8: 你可以使用内置的java.time.format.DateTimeFormatter来减少任何拼写错误的机会, 像< / p >

DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;

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

'Z'Z不一样

'Z'只是一个字符字面值,而Z是零时区偏移量的时区指示器。它代表Zulu,并指定了Etc/UTC时区(具有+00:00小时的时区偏移量)。

因此,在模式中不使用'Z'用于解析/格式化。

java.time,现代Date-Time API

现代Date-Time API基于ISO 8601,只要Date-Time字符串符合ISO 8601标准,就不需要显式使用DateTimeFormatter对象。Date-Time字符串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是零时区偏移量的时区指示器。它代表Zulu,并指定了Etc/UTC时区(具有+00:00小时的时区偏移量)。

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

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

你甚至可以使用ZonedDateTime#withZoneSameInstantZonedDateTime的对象从一个时区转换到另一个时区,例如,下面的代码将把zdt转换为代表印度日期和时间的ZonedDateTime对象:

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

由于任何原因,如果你需要将这个Instant的对象转换为java.util.Date的对象,你可以这样做:

Date date = Date.from(instant);

你甚至可以将OffsetDateTimeZonedDateTime的对象转换为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))开始的< >强毫秒< / >强的个数。由于它不保存任何时区信息,它的toString函数应用JVM的时区来返回一个String,格式为EEE MMM dd HH:mm:ss zzz yyyy,派生自这个< >强毫秒< / >强值。为了获得不同格式和时区的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,你可以使用< em > < >强ThreeTen-Backport < /强> < / em >,它将大部分java.time功能向后移植到Java 6 &7. 如果你正在为一个Android项目工作,而你的Android API级别仍然不符合Java-8,检查通过糖化可获得Java 8+ api如何在Android项目中使用ThreeTenABP。 < /一口> < / p >

现有格式化程序的参考示例:

String date1 = "2022-06-19T01:26:05.000+00:00";
// internally using DateTimeFormatter.ISO_OFFSET_DATE_TIME
System.out.println(OffsetDateTime.parse(date1));


//internally using DateTimeFormatter.ISO_ZONED_DATE_TIME
System.out.println(ZonedDateTime.parse(date1));


String date2 = "2022-06-19T01:26:05";
//internally using DateTimeFormatter.ISO_LOCAL_DATE_TIME)
System.out.println(LocalDateTime.parse(date2));


String date3 = "2022-06-19T01:26:05.00Z";
//internally using DateTimeFormatter.ISO_INSTANT
System.out.println(Instant.parse(date3));

输出:

2022-06-19T01:26:05Z
2022-06-19T01:26:05Z
2022-06-19T01:26:05
2022-06-19T01:26:05Z