UTC日期解析Java中的不一致 [英] UTC date parsing inconsistency in Java

查看:172
本文介绍了UTC日期解析Java中的不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

解析 UTC / GMT 日期时,奇怪的是发生了。我将日期格式设置为

 yyyy-MM-dd'T'HH:mm:ss'Z

其中 Z 用于 UTC 。我给出以下日期字符串来解析:

  String startTimestampString =2013-10-02T00:00:00Z; 

我希望得到与输出相同的日期,而是显示

  2013-10-01 17:00:00.0 

现在确定这个7小时滞后的地方?



代码:

  import java.sql.Timestamp; 
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

public class DateTest {

public static void main(String [] args)throws ParseException {
SimpleDateFormat date = new SimpleDateFormat(yyyy-MM-dd T'HH:mm:ss'Z);
date.setTimeZone(TimeZone.getTimeZone(UTC));
System.out.println(TimeZone.getTimeZone(UTC)。toString());

String startTimestampString =2013-10-02T00:00:00Z;
long startTimestamp = date.parse(startTimestampString).getTime();
System.out.println(String.format(Long%d and timestamp%s,startTimestamp,new Timestamp(startTimestamp).toString()));
}
}

输出: p>

  sun.util.calendar.ZoneInfo [id =UTC,offset = 0,dstSavings = 0,useDaylight = false,transitions = 0,lastRule = null] 
长1380672000000和时间戳2013-10-01 17:00:00.0 //错误时间戳应该是2013-10-02 00:00:00.0


解决方案

java.util.Date没有时区



正如评论所述,您的问题不是理解java.util.Date工作的混乱方式。


A 日期对象没有时区,但 em>有一个,因为它的 toString 方法在生成文本表示(返回的String)时应用您的JVM的默认时区。


Java团队的这种糟糕的设计选择引起了如此多的混乱,包括StackOverflow上的无数类似问题。



日期不是字符串



这里的一个关键思想是,由 toString 方法是一个全新的对象。该字符串不是日期。该字符串是从您的默认时区看到的历史中那一刻的特定表示。历史上的同一时刻,从巴黎或蒙特利尔或加尔各答时区可以看出是两种不同的时间价值。



避免使用java.util.Date



不要浪费你的时间与java.util.Date和.Calendar和SimpleDateFormat。他们是臭名昭着的麻烦。使用 Joda-Time 或新的 java.time包 Java 8 (灵感来自Joda-Time)。



Joda-Time



Joda-Time 2.3中的示例代码。您的格式符合标准 ISO 8601 格式。 Joda-Time使用ISO 8601作为其默认值,因此在您的情况下不需要解析器/格式化程序。 Joda-Time自动使用内置格式化程序来解析符合ISO 8601的字符串。

  String input =2013-10-02T00: 00:00Z; 
DateTimeZone timeZoneParis = DateTimeZone.forID(Europe / Paris);
DateTime dateTimeParis = new DateTime(input,timeZoneParis);
DateTimedateTimeMontréal= dateTimeParis.withZone(DateTimeZone.forID(America / Montreal));
DateTime dateTimeIndia = dateTimeParis.withZone(DateTimeZone.forID(Asia / Kolkata));
DateTime dateTimeUtc = dateTimeParis.withZone(DateTimeZone.UTC);

DateTimeFormatter formatter = DateTimeFormat.forStyle(FF).withLocale(Locale.CANADA_FRENCH);

转储到控制台...

  System.out.println(dateTimeParis:+ dateTimeParis); 
System.out.println(dateTimeMontréal:+dateTimeMontréal);
System.out.println(dateTimeMontréalformatted:+ formatter.print(dateTimeMontréal));
System.out.println(dateTimeIndia:+ dateTimeIndia);
System.out.println(dateTimeUtc:+ dateTimeUtc);

运行时

  dateTimeParis:2013-10-02T02:00:00.000 + 02:00 
dateTimeMontréal:2013-10-01T20:00:00.000-04:00
dateTimeMontréal格式:mardi 1 octobre 2013 20 h 00 EDT
dateTimeIndia:2013-10-02T05:30:00.000 + 05:30
dateTimeUtc:2013-10-02T00:00:00.000Z


Something weird is happening while parsing a UTC/GMT date. I set the date format as

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

where Z is for UTC. And I give following date string to parse:

String startTimestampString = "2013-10-02T00:00:00Z";

I hope to get same date as output but instead it shows

2013-10-01 17:00:00.0

Now sure from where this 7 hour lag coming from?

Code:

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

public class DateTest {

    public static void main(String[] args) throws ParseException {
       SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
       date.setTimeZone(TimeZone.getTimeZone("UTC"));
       System.out.println(TimeZone.getTimeZone("UTC").toString());

       String startTimestampString = "2013-10-02T00:00:00Z";
       long startTimestamp = date.parse(startTimestampString).getTime();
       System.out.println(String.format("Long %d and timestamp %s", startTimestamp, new Timestamp(startTimestamp).toString()));        
    }
}

Output:

sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
Long 1380672000000 and timestamp 2013-10-01 17:00:00.0    // ERROR timestamp should have been 2013-10-02 00:00:00.0

解决方案

java.util.Date Has No Time Zone

As the comments said, your problem is not understanding the confusing way in which java.util.Date works.

A Date object has no time zone, but seems to have one because its toString method applies your JVM's default time zone when generating the textual representation (the String being returned).

This poor design choice by the Java team has caused so much confusion, including countless similar Questions on StackOverflow.

The Date Is Not The String

A key idea here is that the String generated by the toString method is an entirely new object. This string is not the Date. The string is a particular representation of that moment in history as seen from you default time zone. The same moment in history appears as two different time-of-day values when seen from the Paris or Montréal or Kolkata time zones.

Avoid java.util.Date

Do not waste your time with java.util.Date and .Calendar and SimpleDateFormat. They are notoriously troublesome. Use Joda-Time or new java.time package in Java 8 (inspired by Joda-Time).

Joda-Time

Example code in Joda-Time 2.3. Your format is in the standard ISO 8601 format. Joda-Time uses ISO 8601 as its defaults, so no need for parsers/formatters in your case. Joda–Time automatically uses built-in formatters to parse ISO 8601 compliant strings.

String input = "2013-10-02T00:00:00Z";
DateTimeZone timeZoneParis = DateTimeZone.forID( "Europe/Paris" );
DateTime dateTimeParis = new DateTime( input, timeZoneParis );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );
DateTime dateTimeIndia = dateTimeParis.withZone( DateTimeZone.forID( "Asia/Kolkata" ) );
DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );

DateTimeFormatter formatter = DateTimeFormat.forStyle( "FF" ).withLocale( Locale.CANADA_FRENCH );

Dump to console…

System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );
System.out.println( "dateTimeMontréal formatted: " + formatter.print( dateTimeMontréal ) );
System.out.println( "dateTimeIndia: " + dateTimeIndia );
System.out.println( "dateTimeUtc: " + dateTimeUtc );

When run…

dateTimeParis: 2013-10-02T02:00:00.000+02:00
dateTimeMontréal: 2013-10-01T20:00:00.000-04:00
dateTimeMontréal formatted: mardi 1 octobre 2013 20 h 00 EDT
dateTimeIndia: 2013-10-02T05:30:00.000+05:30
dateTimeUtc: 2013-10-02T00:00:00.000Z

这篇关于UTC日期解析Java中的不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆