【问题标题】:How can i convert time zone string to the TimeZone Object in java?如何在 java 中将时区字符串转换为 TimeZone 对象?
【发布时间】:2017-10-04 20:07:53
【问题描述】:

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

我尝试通过ZoneId进行如下转换,但没有成功:

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

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

【问题讨论】:

  • 哦,很抱歉犯了笔误。应该是“UTC+08:00”和“Asia/Shanghai”之间的映射,而不是“UTC+05:00”和“Asia/Shanghai”之间的映射。您的详细回答和温馨提示帮了我很多,非常感谢!
  • 请提供更多上下文。从这个问题来看,我认为可能有比将字符串UTC+08:00 转换为TImeZone 更好的解决方案。你从哪里得到的字符串?你想用TimeZone 做什么?
  • 我得到了诸如“2017-05-05 05:05”之类的日期字符串,它是诸如“UTC+08:00”之类的区域字符串,我需要timeZone对象来组装SimpleDateFormat对象,并且然后解析日期字符串` SimpleDateFormat fromFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); fromFormat.setTimeZone(timeZone);日期 resultDate = format.parse(date)`
  • 感谢您的上下文。在这种情况下,如果有任何方法可以使用 java.time 包中的较新类,您很可能会想要。它们通常不易出错且使用起来更方便,它们也更适合您的特定工作。您可以使用其中一个答案,然后使用LocalDateTime.parse(yourDateString, DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm")).atOffset(zoneOffsetFromAnswer) 或….atZone(zoneIdFromAnswer)。您也可以转换为Instant(甚至转换为Date,但您将尝试看看是否可以避免使用过时的Date 类)。
  • 据我了解您真正需要获得什么,您无需将UTC+08:00 映射到Asia/Shanghai。您只需要在UTC+08:00 的时区或区域偏移中解释您的日期时间字符串。

标签: java date timezone zoneinfo


【解决方案1】:

如果去掉 UTC,可以将其解析为 ZoneOffset,它扩展了 ZoneId

ZoneId zoneId = ZoneOffset.of("+08:00")

【讨论】:

  • 虽然技术上正确,但将ZoneOffset 分配给ZoneId 具有误导性。 ZoneId 类旨在表示一个完整的时区,而时区是偏移量的集合,即特定区域使用的偏移量的更改历史记录。 ZoneOffsetZoneId 之间的子类关系是为了方便 java.time 框架的内部,通常不应在此答案中看到的应用程序中使用。
  • @BasilBourque JavaDoc 表示 ZoneId 用于这两个目的。 “ZoneId 用于识别用于在 Instant 和 LocalDateTime 之间转换的规则。有两种不同类型的 ID [...]”ZoneRegion 是时区区域的另一个子类。
  • 我认为您仍然需要解释这将如何帮助提问者(当然会)。
【解决方案2】:

tl;博士

  • 不要不要使用TimeZone 类(现在是旧版)。
  • 请改用ZoneOffsetZoneId

例子:

ZoneOffset.of( "+08:00" )

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

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

offset-from-UTC 是在UTC 之前或之后调整的小时数和分钟数。这由ZoneOffset 类表示。

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

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

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

不要猜测时区

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

+08:00 的偏移量为例。该偏移量当前由several different time zones 使用,包括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() ;

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

【讨论】:

    【解决方案3】:

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

        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,以备不时之需。 sn-p 打印

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

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

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

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

        Date d = Date.from(i);
    

    老班很麻烦

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

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

    人们可能仍然想知道像UTC+08:00 这样的简单时区怎么会“无法理解”。

    【讨论】:

      猜你喜欢
      • 2011-06-02
      • 2016-05-15
      • 1970-01-01
      • 2015-05-24
      • 2020-04-19
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多