【问题标题】:Java SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") gives timezone as ISTJava SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") 将时区作为 IST
【发布时间】:2013-10-07 09:17:09
【问题描述】:

我有 SimpleDateFormat 构造函数

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

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

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

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

【问题讨论】:

  • 是的,这就是“Z”代表的意思。 Z-时区
  • Z = 祖鲁时间 => GMT+0,你显然没有为你的国家服务;)
  • 请考虑将接受的答案更改为“AZ_”的答案(== 使用 Instant)。如果有库支持这个确切的用例,为什么还要额外的魔法?

标签: java date timezone date-format simpledateformat


【解决方案1】:

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

将时区设置为格林威治标准时间,它将是正确的。

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

【讨论】:

  • 如果你有一个日期,比如没有 Z 的 2012-12-06T06:00:00,那是否代表 GMT?
  • @binarygiant 你得问问那些发送它的人。它可能是发件人的当地时间。
  • 时区可以设置为“UTC”
  • 不要在这么多地方为不同的库设置时区并避免与您的机器/笔记本电脑时区冲突,您应该始终通过设置 user.timezone 系统属性来设置 JVM 的默认时区:java - Duser.timezone=GMT ...
【解决方案2】:

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

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

【讨论】:

  • Subir,感谢您的回答,但输入字符串后附加的“0700”是什么??
  • -0700 是时区,即 -7:00 小时
  • 对于 -07:00 小时而不是 -0700,它将是以下内容:yyyy-MM-dd'T'HH:mm:ss.SSSXXX
【解决方案3】:

从 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 标准 (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

【讨论】:

  • 它给了我 java.text.ParseException: Unparseable date: "2018-05-01T18:30:00.000Z" @AZ_
【解决方案4】:

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

注意末尾的XIt will handle timezones in ISO 8601 standard,而 ISO 8601 正是在 Javascript new Date().toJSON() 中产生此语句的原因

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

  1. 您不需要要求您的客户以格林威治标准时间发送日期
  2. 您无需使用以下命令将 Date 对象显式转换为 GMT:sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

【讨论】:

  • 我使用play的自动表单绑定,并使用@Format.DateTime注解。在结尾使用带有Z 的默认模式似乎是不正确的。改成X后就可以了。非常感谢
  • 如果您的日期以符合 RFC822 的方式指定时区,例如“-0500”,则可以正常工作。但是对于诸如“2013-07-15T10:22:17-05:00”(也是有效的 ISO8601 TZ)之类的日期,这会中断。在这种情况下,您需要使用“yyyy-MM-dd'T'HH:mm:ssXXX”。
  • "yyyy-MM-dd'T'HH:mm:ssX" 应该是准确的答案。 2013-09-29T18:46:19Z 没问题。 'Z' = UTC = +00 = +0000=+00:00
【解决方案5】:

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 框架所取代。见Tutorial避免使用旧的类,因为它们已被证明设计不佳、令人困惑且麻烦。

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

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

InstantUTC 时间线上的一个时刻。

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

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

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

【讨论】:

    【解决方案6】:

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

    X 生成:+01

    XXX 生成:+01:00

    【讨论】:

    • 这真的很有帮助。我正在使用这种格式的日期 2021-04-25T11:12:45+00:00 并且这个 XXX 有帮助:)
    【解决方案7】:

    '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#withZoneSameInstantZonedDateTime 的对象从一个时区转换为另一个时区,例如以下代码会将zdt 转换为ZonedDateTime 的对象,表示印度的日期和时间:

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

    注意#2:出于任何原因,如果您需要将此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 了解有关 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 desugaringHow to use ThreeTenABP in Android Project

    【讨论】:

      【解决方案8】:

      对于 Java 8: 您可以使用内置的java.time.format.DateTimeFormatter 来减少任何拼写错误的机会, 喜欢

      DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;
      

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

      【讨论】:

      • 在 Android 上,这需要应用程序在 API 26 以上运行
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多