我需要将GMT
转换为亚利桑那时间。亚利桑那州目前有MST
(夏令时关闭)。
但是在Joda Time DateTimeZone
代码中,MST
已映射到America/Denver
:
map.put("MST", "America/Denver");
可以看出,目前丹佛有夏令时,因此有MDT
。
那么为什么在DateTimeZone
代码中进行了这样的映射?
从GMT
转换为亚利桑那州的本地时区时,由于GMT-6
错误而应该是GMT-7
,因为MST
没有Daylight节省。
这是一个错误吗? 如何解决这个问题?
答案 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
如果可能的话,我建议您使用新的日期/时间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中,您可以使用自定义MST
将Map
映射到所需的时区:
// 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