将PST转换为CST和EST未提供正确的输出

时间:2018-06-13 22:20:52

标签: java datetime timezone datetime-conversion

我正在尝试为我的应用创建一个正确的转换方法,它将获得PST输入,并可以将其转换为CST或EST,并且还支持夏令时。

这是问题所在。检查以下代码和输出。我只是将我的PST日期转换为CST和EST并打印它。但输出CST和EST中的相同。需要有1小时的差异,但它没有反映出来。

    System.out.println("CURRENT in PST : " + new Date());
    SimpleDateFormat utcDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    utcDateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
    System.out.println("convert in PST : " + utcDateFormat.format( new Date()));

    utcDateFormat.setTimeZone(TimeZone.getTimeZone("CST"));
    System.out.println("convert in CST : " + utcDateFormat.format(new Date()));

    utcDateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
    System.out.println("convert in EST : " + utcDateFormat.format(new Date()));

OutPut:

CURRENT in PST : Wed Jun 13 15:14:15 PDT 2018
convert in PST : 2018-06-13T15:14:15Z
convert in CST : 2018-06-13T17:14:15Z
convert in EST : 2018-06-13T17:14:15Z

任何人都可以告诉我为什么?并且如何我可以完美地为美国的所有时区进行此转换。

我使用 EST5EDT 并且它有效,但不知道它会在夏令时开始或结束时支持。 我可以使用JAVA 8.

1 个答案:

答案 0 :(得分:3)

TL;博士

  

我如何能够完美地为美国的所有时区进行此转换。

Instant now = Instant.now() ;  // Capture current moment in UTC.
ZonedDateTime zdtLosAngeles = now.atZone( ZoneId.of( "America/Los_Angeles" ) ) ;
ZonedDateTime zdtChicago = now.atZone( ZoneId.of( "America/Chicago" ) ) ;
ZonedDateTime zdtNewYork = now.atZone( ZoneId.of( "America/New_York" ) ) ;
ZonedDateTime zdtGuam = now.atZone( ZoneId.of( "America/Guam" ) ) ;
ZonedDateTime zdtHonolulu = now.atZone( ZoneId.of(  "America/Los_Angeles" ) ) ;
ZonedDateTime zdtAnchorage = now.atZone( ZoneId.of( "America/Anchorage" ) ) ;
ZonedDateTime zdtIndianapolis = now.atZone( ZoneId.of( "America/Indiana/Indianapolis" ) ) ;
ZonedDateTime zdtPortOfSpain = now.atZone( ZoneId.of( "America/Port_of_Spain" ) ) ;
ZonedDateTime zdtPhoenix = now.atZone( ZoneId.of( "America/Phoenix" ) ) ;

......等等通过美国的list of the many time zones

Date是UTC

  

" PST中的当前:" +新日期()

这是不正确的;这段代码的表现并不像你显然期望的那样。您可能获取Wed Jun 13 15:58:37 PDT 2018之类的字符串,或者您可能不会。

根据定义,java.util.Date始终为UTC。定义为自UTC 1970年第一时刻的纪元参考以来的毫秒数。您生成的输出字符串可能位于西海岸时间,但这只是偶然的。

令人困惑的部分是,遗憾的是,Date::toString方法被设计为动态地注入JVM的当前默认时区,同时生成一个String来表示此Date对象的值。 如果您的JVM恰好具有某个区域的当前默认时区,例如America/Los_Angeles,您将获得一个美国西海岸时间字符串。但是如果设置了默认时区,那么你的结果会在运行时变化,而你的" CURRENT在PST:"标签不正确。请记住,JVM当前的默认时区可以在运行期间随时通过JVM中任何应用程序的任何线程中的任何代码进行更改。

传统的日期时间类充满了如此糟糕的设计选择。避免使用这些类。

java.time

现代方法使用 java.time 类而不是那些麻烦的旧遗留日期时间类。

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

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

应用time zoneZoneId)获取ZonedDateTime个对象。同一时刻,时间轴上的同一点,但通过某个地区人民使用的挂钟时间来查看。

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

ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

作为一种快捷方式,您可以通过调用Instant并传递ZonedDateTime.now来跳过ZoneId对象。

ZonedDateTime zdt = ZonedDateTime.now( z ) ;
  

我如何才能完美地完成美国所有时区的转换。

首先,从不使用伪区“PST”,“CST”,“EST”如上所述。使用实时区域。

美国有三个以上的区域,例如America/ChicagoAmerica/New_YorkAmerica/Fort_WaynePacific/HonoluluAmerica/Puerto_Rico等等。为什么这么多?因为当前和过去的做法各不相同。例如,美国的某些地方选择退出Daylight Saving Time (DST)的愚蠢。各个地方都有各种各样的历史,其中offset-from-UTC在该区域被人们在其历史中的不同点改变。

其次,保持您的时区定义是最新的。大多数软件系统使用IANA发布的tzdata(以前称为 Olson数据库)的副本。您的主机操作系统,JVM实施和数据库服务器可能都有tzdata的副本,如果您关心的任何区域的规则发生变化,则必须保持最新状态。

永远不要忽略区域/偏移

  

" YYYY-MM-DD' T' HH:MM:SS' Z'"

您的格式化模式在Z周围放置单引号时做出了可怕的选择。 Z表示UTC,发音为Zulu。您的单引号告诉格式化程序忽略该特定字符串,就好像它没有意义一样。但它 not 毫无意义,它是关于您选择忽略和丢弃的输入数据的重要信息。

另一件事......该特定格式由ISO 8601标准定义。 java.time 类在解析/生成字符串时默认使用这些标准格式。

Instant.parse( "2018-01-23T12:34:56Z" )  // Parse standard ISO 8601 string into a `Instant` object.

instant.toString() // Yields "2018-01-23T12:34:56Z".

关于 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