5

我有几个 UTC 格式的时区字符串,例如"UTC+08:00", "UTC-05:00",问题是如何将这些 utc 格式的字符串转换为java.util.TimeZoneJava 格式的字符串?

我尝试ZoneId按如下方式进行转换,但它不起作用:

ZoneId zoneId = ZoneId.of("UTC+08:00");
TimeZone timeZone = TimeZone.getTimeZone(zoneId);

我知道TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");会起作用,但我不知道和之间的"UTC+08:00"映射"Asia/Shanghai"

4

3 回答 3

8

tl;博士

  • 不要使用类(现在是TimeZone旧版)。
  • 使用ZoneOffsetandZoneId代替。

例子:

ZoneOffset.of( "+08:00" )

使用java.time.ZoneId,而不是TimeZone

与 Java 的最早版本捆绑在一起的麻烦的旧日期时间类现在是遗留的,被 java.time 类所取代。在这些旧的遗留类中,现在被andTimeZone取代。ZoneIdZoneOffset

与 UTC的偏移是在 UTC之前或之后调整的小时数和分钟数。这由ZoneOffset类表示。

时区是偏移量的集合,特定区域用于确定其挂钟时间的偏移量变化历史。这由ZoneId类表示。

使用时区总是比偏移量更可取,因为区域具有偏移量以及更多信息。但是您的示例只是偏移量。所以ZoneOffset在删除字符后使用 来解析字符串UTC

String input = "UTC+08:00".replace( "UTC" , "" ) ;
ZoneOffset offset = ZoneOffset.of( input ) ;

不要猜测时区

您不能假设特定的偏移量意味着特定的时区。许多区域可能在过去、现在或将来使用了特定的偏移量。所以你不应该猜测区域。

以 的偏移量为例+08:00。该偏移量目前被几个不同的时区使用,包括Asia/ShangaiAsia/MacaoAustralia/Perth

如果您确定某个特定区域用于日期时间值,请将其应用以获取ZonedDateTime. 但不要猜测。

该类Instant表示 UTC 时间线上的一个时刻,分辨率为纳秒。

Instant instant = Instant.now() ;
ZoneId z = ZoneId.of( "Asia/Shanghai" ) ; 
ZonedDateTime zdt = instant.atZone( z ) ;

如果您不确定预期的时区并且只有一个偏移量,请使用偏移量来获取OffsetDateTime.

Instant instant = Instant.now() ;
ZoneOffset offset = ZoneOffset.of( "+08:00" ) ; 
OffsetDateTime odt = instant.atOffset( offset ) ;

兑换

最好避免旧的遗留类TimeZone。但是,如果您必须使用该类来处理尚未为 java.time 类更新的旧代码,您可以转换为/从ZoneId. 使用添加到旧类的新转换方法。

TimeZone myLegacyTimeZone = TimeZone.getTimeZone( myModernZoneId ); 

…和…

ZoneId z = myLegacyTimeZone.toZoneId() ;

请注意,它ZoneOffset是 的子类ZoneId。通常,我们忽略这种继承关系。如果您只有一个偏移量,例如+08:00,请使用ZoneOffset. 如果您有完整的时区,例如Asia/Shanghai,请使用ZoneId. 该规则的一个例外是这种到/从只识别TimeZone超类的转换。ZoneId

于 2017-05-06T14:05:06.413 回答
2

如果剥离 UTC,则可以将其解析为 ZoneOffset,它扩展了 ZoneId

ZoneId zoneId = ZoneOffset.of("+08:00")
于 2017-05-06T12:38:25.310 回答
0

由于您可以使用java.time包中的现代类,我建议您坚持使用它们并避免使用过时的类,如TimeZone,SimpleDateFormatDate. 我主要是在重复@Basil Bourque 在他的回答中已经说过的话,但也想证明他的建议非常适合您的上下文:

    DateTimeFormatter format = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm");
    ZonedDateTime dateTime = LocalDateTime.parse(dateTimeString, format).atZone(zoneId);
    Instant i = dateTime.toInstant();
    System.out.println(dateTime + " -> " + i);

我还证明了您可以将 转换为ZonedDateTime以防Instant万一。片段打印

2017-05-05T05:05+08:00[UTC+08:00] -> 2017-05-04T21:05:00Z

如果您确定您的日期时间字符串和您的区域字符串属于一起,则无需从区域字符串的开头String.replace()删除UTC

我独立于时区解析字符串,然后将其与区域偏移信息结合起来。我认为这比必须知道解析区域更自然。

如果您需要 oldfashioned Date,例如调用一些遗留代码,这很容易:

    Date d = Date.from(i);

老班很麻烦

即使我知道旧课程倾向于表现出不受欢迎的行为而没有告诉您任何错误,但得知您问题中的代码不起作用,我仍然感到惊讶。它给出了格林威治标准时间的时区!但是,在以下文档中记录了这是一种可能性TimeZone.getTimeZone(ZoneId)

返回:
指定的时区,如果给定的 ID 无法理解,则返回 GMT 时区。

UTC+08:00人们可能仍然想知道如何“不理解”像这样的简单时区。

于 2017-05-07T06:07:22.977 回答