MST映射到joda的丹佛时区,目前是MDT。这是joda DateTimeZone中的错误吗?

时间:2017-03-26 11:15:14

标签: java jodatime timezone-offset

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

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

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

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

GMT转换为亚利桑那州的本地时区时,由于GMT-6错误而应该是GMT-7,因为MST没有Daylight节省。

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

2 个答案:

答案 0 :(得分:1)

起初我认为Joda时间将使用相同的TimeZone ID作为基础Java的TimeZone。我通过代码调试,发现它有点复杂。虽然可能与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);

}

答案 1 :(得分:1)

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

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

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

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

此地图仅用于DateTimeZone.forTimeZone(TimeZone),这是一种将旧TimeZone类转换为jodatime&#39; s DateTimeZone的方法(对我来说,确认兼容性原因)

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

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

示例代码:

// 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 Time API

如果可能的话,我建议您使用新的日期/时间API(如果无法从Joda-time迁移到这个新的API,请考虑其余的答案;但如果您想要迁移它,请继续)。

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

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

如果您正在使用 Java&lt; = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ThreeTenABP(更多关于如何使用它here)。

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

在新的API中,您可以使用自定义MSTMap映射到所需的时区:

// 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