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

Converting PST to CST and EST not giving proper output

我正在尝试为我的应用程序创建一个正确的转换方法,它将以 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()));

输出:

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.

tl;博士

how I can do this conversion perfectly for all timezones of USA.

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

"CURRENT in PST : " + new Date()

这是不正确的;此代码的行为并不像您显然期望的那样。你可能得到一个字符串,例如Wed Jun 13 15:58:37 PDT 2018,也可能不会。

根据定义,

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

令人困惑的部分是,不幸的是,Date::toString 方法被设计为动态注入 JVM 当前的默认时区,同时生成一个字符串来表示此 Date 对象的值。 如果 您的 JVM 碰巧有一个当前默认时区,例如 America/Los_Angeles,您将得到一个带有美国西海岸时间的字符串。但是,如果默认时区设置不正确,您的结果将在运行时发生变化,并且您的 "CURRENT in PST:" 标签将不正确。请记住,JVM 中任何应用程序的任何线程中的任何代码都可以在运行时的任何时刻更改 JVM 的当前默认时区。

遗留的日期时间 类 充斥着如此糟糕的设计选择。避免使用这些 类.

java.time

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

Instant 替换 java.util.DateInstant class represents a moment on the timeline in UTC with a resolution of nanoseconds(最多九 (9) 位小数)。

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

应用 time zone (ZoneId) 得到一个 ZonedDateTime 对象。同一时刻,时间轴上的同一点,但通过某个地区的人们使用的挂钟时间来看。

指定 proper time zone name in the format of continent/region, such as America/Montreal, Africa/CasablancaPacific/Auckland。切勿使用 ESTIST 等 3-4 个字母的伪时区,因为它们 不是 真实时区,未标准化,甚至不唯一(! ).

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

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

ZonedDateTime zdt = ZonedDateTime.now( z ) ;

And how I can do this conversion perfectly for all timezones of USA.

首先,切勿使用上面讨论的伪区“PST”、“CST”、“EST”。使用实时区域。

美国的三区有很多,比如America/ChicagoAmerica/New_YorkAmerica/Fort_WaynePacific/HonoluluAmerica/Puerto_Rico、很快。为什么这么多?因为当前和过去的做法有所不同。例如,美国的一些地方选择退出该地区 Daylight Saving Time (DST). Various places have various histories where the offset-from-UTC 的愚蠢行为,这些地方在其历史的不同时期被人们改变了。

其次,使您的时区定义保持最新。大多数软件系统使用 tzdata (formerly known as Olson Database) published by IANA. Your host OS, your JVM 实现的副本,并且您的数据库服务器可能都有一个 tzdata 副本,如果您关心的任何区域的规则发生变化,则必须保持最新。

绝不忽略zone/offset

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

您的格式设置模式在 Z 周围放置单引号是一个糟糕的选择。 Z 表示 UTC,发音为 Zulu。您的单引号告诉格式化程序忽略该特定字符串,就好像它没有意义一样。但它 而不是 没有意义,它是有关您选择忽略和丢弃的输入数据的重要信息。

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

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 framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time 类.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

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

在哪里获取java.time类?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.