您可以使用org.joda.time.DateTimeZone
班级。它包含有关世界上所有时区的 DST 更改的信息,因此您无需检测 DST 更改:如果您正确告知您正在使用哪个时区,则 API 会为您完成这项工作。
当您使用英国时区时,您可以直接使用Europe/London
时区 - 这些名称的格式Continent/City
来自IANA 数据库 https://www.iana.org/time-zones,它被 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 的大型代码库或者不想迁移它现在,您可以考虑答案的其余部分。
无论如何,即使在乔达的网站 http://www.joda.org/joda-time它说:“请注意,Joda-Time 被认为是一个很大程度上“完成”的项目。没有计划进行重大增强。如果使用 Java SE 8,请迁移到 java.time (JSR-310)。”.*
如果您正在使用Java 8,考虑使用新的 java.time API https://docs.oracle.com/javase/tutorial/datetime/。更容易,与旧 API 相比,漏洞较少且不易出错 https://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api。我不确定它是否已适用于所有 Android 版本(但请参阅下面的替代方案)。
如果您正在使用Java ,您可以使用三十向后移植 http://www.threeten.org/threetenbp/,Java 8 新日期/时间类的一个很好的向后移植。而对于Android,有一种方法可以使用它,通过三十ABP https://github.com/JakeWharton/ThreeTenABP(更多关于如何使用它here https://stackoverflow.com/a/38922755/7605325).
下面的代码适用于两者。
唯一的区别是包名称(在 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()
and start.until()
) 返回12
。根据javadoc https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#between-java.time.temporal.Temporal-java.time.temporal.Temporal-, between
and until
是等价的,因为第一个只是在内部调用第二个 http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/43cb25339b55/src/share/classes/java/time/temporal/ChronoUnit.java#l270。用一个Duration
也是等效的,因为它使用它们之间的纳秒并将其转换为小时。