为什么某些日期在格式化日期时显示为BST而某些日期显示为GMT?

时间:2017-12-05 15:03:27

标签: java date parsing timezone simpledateformat

我有以下两个输入字符串:

String string1 = "2017-01-30T13:00:00+0000"
String string2 = "2018-06-23T16:00:00+0000"

对于string1,当我这样做时,我会关注以下日期:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date startDate = formatter.parse(string1);

结果 - Mon Jan 30 13:00:00 GMT 2017

但是当我为string2做同样的事情时,我在调试器中得到以下内容:

Sat Jun 23 17:00:00 BST 2018

为什么我在这里获得不同的时区?

1 个答案:

答案 0 :(得分:2)

TL;博士

OffsetDateTime.parse( "2017-01-30T13:00:00+0000" )

java.time

您使用的麻烦的旧遗留类的许多设计缺陷中,Date::toString方法在生成字符串时应用JVM的当前默认时区。因此,虽然内部的值实际上是UTC,但它容易混淆地显示另一个时区。除此之外,您当前的默认时区经历了两个日期之间的夏令时切换。

而是使用现代java.time类。将输入字符串解析为OffsetDateTime个对象。

OffsetDateTime odt = OffsetDateTime.parse( "2017-01-30T13:00:00+0000" ) ; 

Java 8和Java 9中的一个错误可能会在解析你的UTC偏移量时缺少小时和分钟之间的冒号。解决方法是添加冒号。

OffsetDateTime odt = OffsetDateTime.parse( "2017-01-30T13:00:00+0000".replace( "+0000" , "+00:00" ) ; 

调用toString以标准ISO 8601格式生成字符串。与Date不同,动态应用的任何时区的结果都会被掺假。

如果需要,请指定ZoneId以获取ZonedDateTime

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

ZoneId z = ZoneId.of( "Europe/London" ) ; 
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

请参阅complete code for both inputs run live at IdeOne.com

String input2017 = "2017-01-30T13:00:00+0000".replace( "+0000" , "+00:00" ) ;  // Workaround Java 8 bug where omitted colon in offset-from-UTC fails to parse. Fixed in Java 9.
OffsetDateTime odt2017 = OffsetDateTime.parse( input2017 ) ; 

String input2018 = "2018-06-23T16:00:00+0000".replace( "+0000" , "+00:00" ) ;  // Workaround Java 8 bug where omitted colon in offset-from-UTC fails to parse. Fixed in Java 9.
OffsetDateTime odt2018 = OffsetDateTime.parse( input2018 ) ; 

ZoneId z = ZoneId.of( "Europe/London" ) ; 
ZonedDateTime zdt2017 = odt2017.atZoneSameInstant( z ) ;
ZonedDateTime zdt2018 = odt2018.atZoneSameInstant( z ) ;

转储到控制台。

System.out.println( "input2017: " + input2017 ) ;
System.out.println( "odt2017: " + odt2017 ) ;
System.out.println( "zdt2017: " + zdt2017 ) ;
System.out.println( "" ) ;  // Blank line.

System.out.println( "input2018: " + input2018 ) ;
System.out.println( "odt2018: " + odt2018 ) ;
System.out.println( "zdt2018: " + zdt2018 ) ;

请注意,在2018年6月,由于Daylight Saving Time (DST)Europe/London时间会向前跳一小时。在冬季,伦敦区域是UTC,但在夏季,UTC的前一小时

2017

  

input2017:2017-01-30T13:00:00 + 00:00

     

odt2017:2017-01-30T13:00Z

     

zdt2017:2017-01-30T13:00Z [欧洲/伦敦]

2018

  

input2018:2018-06-23T16:00:00 + 00:00

     

odt2018:2018-06-23T16:00Z

     

zdt2018:2018-06-23T17:00 + 01:00 [欧洲/伦敦]

搜索Stack Overflow获取更多信息,因为此主题已经处理了很多次。

关于 java.time

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

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

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

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

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