您可以使用org.joda.time.DateTimeZone 类。它包含世界上所有时区的 DST 更改信息,因此您无需检测 DST 更改:如果您正确告知您正在使用哪个时区,API 会为您完成这项工作。
当您使用英国时区时,您可以直接使用Europe/London 时区——Continent/City 格式的这些名称来自IANA database,它被 Joda-Time、Java 和许多其他 API 使用.您可以通过调用DateTimeZone.getAvailableIDs()获取所有时区的列表。
当您使用 DateTimeZone 时,它已经包含历史期间的所有 DST 班次,因此 API 会为您完成所有数学运算。你只需要在这个时区创建你的 DateTime 实例:
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Duration;
// London timezone - it contains all info about DST shifts
DateTimeZone london = DateTimeZone.forID("Europe/London");
// Start on 25/03/2017 13:00
DateTime start = new DateTime(2017, 3, 25, 13, 0, london);
// ends on 26/03/2017 02:00
DateTime end = new DateTime(2017, 3, 26, 2, 0, london);
// get the difference between start and end
Duration duration = new Duration(start, end);
System.out.println(duration.getStandardHours()); // 12
输出将是12(API 使用DateTime 的时区信息来计算差异,包括 DST 偏移)。
你也可以使用:
duration.toStandardHours().getHours()
或班级org.joda.time.Hours:
Hours.hoursBetween(start, end).getHours()
它们都返回12,它们都是等价的。
Java 新的日期/时间 API
Joda-Time 已停用并被新的 API 取代,因此如果您正在考虑迁移,您可以开始使用新的日期/时间 API,但如果您有使用 Joda 的大型代码库或不想要现在要迁移它,您可以考虑其余的答案。
不管怎样,即使在joda's website 中它说:“请注意,Joda-Time 被认为是一个基本上“完成”的项目。没有计划进行重大改进。如果使用 Java SE 8,请迁移到 java。时间(JSR-310)。”.*
如果您使用的是 Java 8,请考虑使用 new java.time API。更简单,less bugged and less error-prone than the old APIs。我不确定它是否已经适用于所有 Android 版本(但请参阅下面的替代方案)。
如果您使用的是 Java ,则可以使用 ThreeTen Backport,这是 Java 8 新日期/时间类的一个很好的向后移植。对于Android,有一种使用方法,即ThreeTenABP(更多关于如何使用它here)。
下面的代码适用于两者。
唯一的区别是包名(在 Java 8 中是 java.time,而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但类和方法 names 是相同的。
新 API 还使用 IANA 时区名称,并包含有关 DST 转换的相同历史信息(获取所有时区列表:ZoneId.getAvailableZoneIds())。代码非常相似,而且获得差异的方法也不止一种:
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
// London timezone
ZoneId london = ZoneId.of("Europe/London");
// Start on 25/03/2017 13:00
ZonedDateTime start = ZonedDateTime.of(2017, 3, 25, 13, 0, 0, 0, london);
// ends on 26/03/2017 02:00
ZonedDateTime end = ZonedDateTime.of(2017, 3, 26, 2, 0, 0, 0, london);
// get the difference in hours
System.out.println(ChronoUnit.HOURS.between(start, end)); // 12
// get the duration in hours
Duration duration = Duration.between(start, end);
System.out.println(duration.toHours()); // 12
// using until() method
System.out.println(start.until(end, ChronoUnit.HOURS)); // 12
上述所有三种方法(ChronoUnit.HOURS.between()、duration.toHours() 和 start.until())都返回 12。根据javadoc,between和until是等价的,as the first just internally calls the second。使用Duration 也是等效的,因为它使用它们之间的纳秒并将其转换为小时。