【问题标题】:MST being mapped to Denver timezone in joda which currently is MDT. Is this a bug in joda DateTimeZone?MST 被映射到 joda 中的丹佛时区,目前是 MDT。这是 joda DateTimeZone 中的错误吗?
【发布时间】:2017-06-13 03:26:53
【问题描述】:

我需要将GMT 转换为亚利桑那时间。亚利桑那州目前有MST(夏令时关闭)。

但是在 Joda Time DateTimeZone 代码中,MST 已映射到 America/Denver

map.put("MST", "America/Denver");

可以看出,目前丹佛开启了夏令时,因此有MDT。 那为什么DateTimeZone代码中会做出这样的映射呢?

在从GMT 转换为亚利桑那州的本地时区时,我得到了GMT-6 的偏移量,这是错误的,应该是GMT-7,因为MST 没有夏令时。

这是一个错误吗? 如何解决问题?

【问题讨论】:

  • 您能明确指定America/Phoenix 吗? (我不知道JodaTime,但我猜应该能看懂。)
  • 如果一切都失败了,您可以考虑切换到 Java 8 java.time 日期和时间类或其向后移植到 Java 6 和 7,ThreeTen Backport。如果您已经有一个使用 JodaTime 的大型代码库,那么这当然不是您想要的。

标签: java jodatime timezone-offset


【解决方案1】:

起初我认为 Joda 时间会使用与基本 Java 的 TimeZone 相同的 TimeZone ID。我通过代码调试,发现它有点复杂。虽然可能与 Joda 使用与基本 Java 相同的 ID,但它实际上是从 joda jar 中的文件加载时区信息。此示例使用所有 Joda 类完成。 dt 出现了亚利桑那州凤凰城时间。

public static void main(String[] args)
{
  //List all time zones
  Set<String> timezones = DateTimeZone.getAvailableIDs();
  for(String tz : timezones)
  {
    System.out.println(tz);
  }

  DateTimeZone arizona = DateTimeZone.forID("US/Arizona");
  DateTimeZone.setDefault(arizona);
  DateTime dt = new DateTime();
  System.out.println(dt);

}

【讨论】:

    【解决方案2】:

    这些 3 字母缩写的问题在于它们是 ambiguous and not standard

    所以,MST 是一个时区名称,可以应用于许多不同的地区,它们可能有不同的 DST 规则(有些可能有 DST,有些可能没有,更不用说历史信息了 - 有些可能 过去有 DST,现在没有了,或者相反)。

    旧 API (java.util.TimeZone) 处理这些歧义,假设这些歧义 3 字母名称的默认值,所以 MST 被映射到 America/Denver 并且这被保存在 joda-time - IMO - for 兼容性 原因(您可以在源代码中看到 - 我使用的是 jodatime 2.7)。至少这是我从评论中可以理解的:

    map.put("MST", "America/Denver");  // JDK 1.1 compatible
    

    而且这个映射只用在DateTimeZone.forTimeZone(TimeZone)中,这是一种将旧的TimeZone类转换为jodatime的DateTimeZone的方法(对我来说,这证实了兼容性的原因)。


    如果您想确保您的代码使用正确的时区,您可以按照@Ole V.V.'s comment 中的说明进行操作,并使用America/Phoenix 而不是MST。这将消除歧义,并使您的代码更清楚地了解它使用的时区。

    这些时区名称 (Continent/City) 来自 IANA database,这是 Java 的 API 和 Joda time 使用的名称。

    示例代码:

    // create a date/time in UTC
    DateTime utc = new DateTime("2017-03-26T10:00:00Z", DateTimeZone.UTC);
    System.out.println(utc); // 2017-03-26T10:00:00.000Z
    
    // convert to Arizona timezone
    DateTimeZone arizona = DateTimeZone.forID("America/Phoenix");
    DateTime arizonaDate = utc.withZone(arizona);
    System.out.println(arizonaDate); // 2017-03-26T03:00:00.000-07:00
    

    新的 Java 时间 API

    如果可能,我建议您使用新的日期/时间 API(如果无法从 Joda-time 迁移到此新 API,请忽略此答案的其余部分;但如果您想迁移它,请继续)。

    joda 的问题是因为在joda's website 中它说:请注意,Joda-Time 被认为是一个基本上“完成”的项目。没有计划进行重大改进。如果使用 Java SE 8,请迁移到 java.time (JSR-310)

    如果您使用的是 Java 8,请考虑使用 new java.time API。更简单,less bugged and less error-prone than the old APIs

    如果您使用的是 Java ,则可以使用 ThreeTen Backport,这是 Java 8 新日期/时间类的一个很好的向后移植。对于Android,还有ThreeTenABP(更多关于如何使用它here)。

    下面的代码适用于两者。 唯一的区别是包名(在 Java 8 中是 java.time,而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但类和方法 names 是相同的。

    在新 API 中,可以使用自定义 MapMST 映射到您想要的时区:

    // custom map with timezone names
    Map<String, String> map = new HashMap<>();
    // map "MST" to Arizona's timezone
    map.put("MST", "America/Phoenix");
    // create timezone
    ZoneId arizona = ZoneId.of("MST", map);
    
    // datetime in UTC
    ZonedDateTime utc = ZonedDateTime.parse("2017-03-26T10:00:00Z");
    System.out.println(utc); // 2017-03-26T10:00Z
    
    // convert to Arizona timezone
    ZonedDateTime arizonaDate = utc.withZoneSameInstant(arizona);
    System.out.println(arizonaDate); // 2017-03-26T03:00-07:00[America/Phoenix]
    

    当然,理想的选择是使用ZoneId.of("America/Phoenix"),但如果不可行,您必须使用MST,自定义地图是一个不错的选择。

    另请注意,新 API 会打印 [] 之间的时区名称。如果要更改它,可以使用DateTimeFormatter 类。您可以使用内置格式化程序(查看javadoc 了解更多信息),或者自己制作:

    // use built-in formatter
    DateTimeFormatter fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
    System.out.println(fmt.format(arizonaDate)); // 2017-03-26T03:00:00-07:00
    
    // use custom format
    fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
    System.out.println(fmt.format(arizonaDate)); // 2017-03-26T03:00:00.000-07:00
    

    【讨论】:

      猜你喜欢
      • 2015-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 2015-04-21
      相关资源
      最近更新 更多