夏令时的持续时间

我有一个对象Shift ,有两个字段: startDateTimeendDateTime作为Joda-Time的DateTime

我的转变包括夏令时英国的变化。 它开始于25/03/2017 13:00 ,结束于26/03/2017 02:00 (基本上应该在26/03/2017 01:00结束,但这个日期不存在,并且endDate转移+1小时)。 根据这个网站 :

当地标准时间即将到达2017年3月26日星期日时,01:00:00时钟转发1小时至2017年3月26日星期日,当地白天时间02:00:00。

现在,如果我想跟踪一个员工的工作小时数new Duration(startDateTime, endDateTime).toStandardHours().getHours()将给我13个小时。

如何使用Joda-Time检测夏令时是否在我的class次持续时间内开始或结束?

您可以使用org.joda.time.DateTimeZone类。 它包含有关世界上所有时区的DST更改的信息,因此您无需检测DST更改:如果您正确通知了您正在使用的时区,则API会为您完成工作。

当您使用英国时区时,您可以直接使用Europe/London时区 – 这些名称为Continent/City名称来自IANA数据库 ,它由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取代,所以如果你正在考虑迁移,你可以开始使用新的Date / Time API,但如果你有一个使用Joda的大代码库或者不想迁移它现在,你可以考虑其余的答案。

无论如何,即使在joda的网站上它也说: “请注意,Joda-Time被认为是一个很大程度上已经完成的项目。没有计划进行重大改进。如果使用Java SE 8,请迁移到java.time(JSR-310)。 “ *。

如果您使用的是Java 8 ,请考虑使用新的java.time API 。 与旧的API相比 ,它更容易, 更少的错误并且更不容易出错 。 我不确定它是否已经可用于所有Android版本(但请参阅下面的替代方案)。

如果您使用Java <= 7 ,则可以使用ThreeTen Backport ,这是Java 8的新日期/时间类的一个很好的后端 。 对于Android ,有一种方法可以使用它,使用ThreeTenABP (更多关于如何在这里使用它)。

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

新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 , betweenuntil是等价的, 因为第一个只是内部调用第二个 。 使用Duration也是等效的,因为它使用它们之间的纳秒并将其转换为小时。

  1. 您应该使用TimeZone ID,例如“Europe / London”
  2. 将开始和结束时间转换为GMT
  3. 现在查找GMT开始和结束时间的持续时间

使用TimeZone ID时会自动处理日光。