2017-07-29 147 views
1

我试图解析日期字符串使用此代码测试时区:SimpleDateFormat.parse()忽略时区?

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZZZZZ", Locale.US); 
Calendar calendar = Calendar.getInstance(); 
calendar.setTime(sdf.parse("2017-07-26T06:00-06:00")); 
int offset = calendar.getTimeZone().getRawOffset(); 

我试图改变时区从-06+09,但offset总是包含10800000

如何正确解析日期与时区(我需要时间和时区两者)?

+0

是的,我是。我从远程服务器获取它,并且无法更改它。我只需要解析它。 – BArtWell

+0

为什么?它完全正常,只是不包含一秒钟。 – BArtWell

+0

'-06:00' - 那不是时候。这是时区。它可以是'-09:00'或'+05:00'或类似的东西。 – BArtWell

回答

1

注意:-06:00是一个offset, not a timezone - 这两个概念是相关的,但它们是不同的东西(更多在下面)。


SimpleDateFormatCalendar的问题是,他们使用系统的默认时区,所以即使您解析的日期用不同的偏移(如-06:00),所产生的Calendar将有默认的时区(你可以检查什么区域是通过调用TimeZone.getDefault())。

这只是这个旧API的许多problemsdesign issues之一。

幸运的是,如果您不介意为项目添加依赖项(在这种情况下,我认为它完全值得),还有更好的选择。在Android中,您可以使用ThreeTen Backport,它是Java 8新日期/时间类的一个很好的后端。而对于Android,您还需要ThreeTenABP才能使其正常工作(更多关于如何使用它here)。

要与补偿工作,你可以使用org.threeten.bp.OffsetDateTime类:

// parse the String 
OffsetDateTime odt = OffsetDateTime.parse("2017-07-26T06:00-06:00"); 

这将正确地分析所有的字段(日期/时间和偏移量)。为了获得偏移值,类似于calendar.getTimeZone().getRawOffset(),你可以这样做:

// get offset in milliseconds 
int totalSeconds = odt.getOffset().getTotalSeconds() * 1000; 

我不得不由1000因为calendar返回值以毫秒为单位,但在几秒钟内ZoneOffset返回到繁殖。

将其转换为另一个偏移(+09:00),这是简单的:

// convert to +09:00 offset 
OffsetDateTime other = odt.withOffsetSameInstant(ZoneOffset.ofHours(9)); 

正如我所说,时区和偏移量是不同的东西:

  • 偏移量是从UTC的区别:-06:00表示“UTC后6小时”,+09:00表示“UTC前9小时”
  • 时区是一个地区在过去(以及当这些变化发生时)具有和将会具有的所有不同的抵消的集合。最常见的情况是Daylight Saving Time班次,当时钟在某个区域前后变化1小时时。所有这些关于何时更改(以及更改前后的偏移量)的规则都由时区概念封装。

所以,上面的代码工作正常,如果你正在处理偏移量并想转换为另一个。但是如果你想用一个时区工作,你必须转换OffsetDateTimeZonedDateTime

// convert to a timezone 
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("Asia/Tokyo")); 
// get the offset 
totalSeconds = zdt.getOffset().getTotalSeconds() * 1000; 

getOffset()上述方法将检查指定的时区的历史和取得的偏移量是在相应的即时激活(因此,例如,如果您在夏令时期间拍摄日期,则会相应调整偏移量(以及日期和时间)。

API使用IANA timezones names(始终格式为Region/City,如America/Sao_PauloEurope/Berlin)。 避免使用3字母缩写(如CST或),因为它们是ambiguous and not standard

通过调用ZoneId.getAvailableZoneIds(),您可以获得可用时区列表(并选择最适合您系统的时区)。

您也可以使用系统的默认时区ZoneId.systemDefault(),但即使在运行时也可以在不通知的情况下对其进行更改,因此最好使用特定的时区。