夏令时的持续时间
我有一个对象Shift
,有两个字段: startDateTime
和endDateTime
作为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 , between
和until
是等价的, 因为第一个只是内部调用第二个 。 使用Duration
也是等效的,因为它使用它们之间的纳秒并将其转换为小时。
- 您应该使用TimeZone ID,例如“Europe / London”
- 将开始和结束时间转换为GMT
- 现在查找GMT开始和结束时间的持续时间
使用TimeZone ID时会自动处理日光。