SimpleDateFormat在解析期间返回错误的时区

时间:2013-04-19 15:15:00

标签: simpledateformat

我在创建Date对象时遇到了一个奇怪的问题。我有以下代码将日期的时区设置为UTC。在解析语句之前我看到sdfDate的时区为UTC但是在解析语句之后我看到punchDate有值:Sat Mar 30 01:00:00 CET 2013,我相信这是来自我的系统。但是,我如何确保即使在解析后时区也保持不变。

Date punchDate = null;
Date punchTime = null;

SimpleDateFormat sdfDate = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");

    try
    {
        sdfDate.setTimeZone(TimeZone.getTimeZone("UTC"));
        sdfTime.setTimeZone(TimeZone.getTimeZone("UTC"));
        punchDate = sdfDate.parse(arg1);
        punchTime = sdfTime.parse(arg2);
    }
    catch (ParseException pe)
    {
        System.out.println("Parse exception " +pe.getMessage());
    }

我的要求基本上是我需要从字符串输入中创建一个Date对象,但时区应保持UTC。

2 个答案:

答案 0 :(得分:3)

TL;博士

  

我需要从字符串输入中创建一个Date对象,但时区应保持UTC。

LocalDate.parse( 
    "23.01.2017" , 
    DateTimeFormatter.ofPattern( "dd.MM.uuuu" ) 
) 

...和...

LocalTime.parse( "12:34:56" ) 

...结合...

OffsetDateTime.of( datePart , timePart , ZoneOffset.UTC )

详细

您正在使用麻烦的令人困惑的旧日期时间类,现在已被java.time类取代。

OffsetDateTime

你说你确定你的输入是用于UTC的,尽管没有这样的指标。因此,我们将解析日期部分,解析时间部分,然后在为offset-from-UTC分配UTC零时进行组合。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd.MM.uuuu" ) ;
LocalDate ld = LocalDate.parse( "23.01.2017" , f ) ;

时间输入恰好符合java.time类中默认使用的标准ISO 8601格式。因此无需指定格式化模式。

LocalTime lt = LocalTime.parse( "12:34:56" ) ;

联合

OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC ) ;

时区

如果您希望看到特定区域的挂钟时间中显示的相同时刻,请应用ZoneId获取ZonedDateTime

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;  // Same simultaneous moment, same point on the timeline.

ISO 8601

提示:要将此类数据作为文本进行交换,请仅使用标准ISO 8601格式。这些格式设计合理,非常明确,易于通过机器处理,并且易于人们阅读多种文化。

在解析和生成字符串时,java.time类默认使用标准格式。

String output = Instant.now().toString() ;  
  

2017-01-23T12:34:56.123456789Z

转换

避免遗留java.util.Date课程。但如果你必须,你可以转换。查看添加到旧类的新方法。

Instant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

通过致电Instant,从OffsetDateTime中提取toString个对象。

Instant instant = odt.toInstant() ;
java.util.Date date = Date.fromInstant( instant ) ;

......走另一条路......

Instant instant = myJavaUtilDate.toInstant() ;
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;  

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:0)

您的日期对象与本地系统时间相同。 您已使用本地时区创建本地日期对象,并将转换后的(UTC)时区分配给本地。

Date punchDate = null;
Date punchTime = null;

所以您的日期值保持不变,但它显示在不同的时区值。