夏令时

2020年8月18日 26点热度 0条评论

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

我的工作包括夏令时的英国更改。它以25/03/2017 13:00开头,以26/03/2017 02:00结束(基本上应该以26/03/2017 01:00结尾,但是此日期不存在,并且endDate偏移了+1小时)。根据此site:

即将达到当地标准时间
2017年3月26日,星期日,01:00:00时钟向前进1个小时,
2017年3月26日,星期日,当地夏令时改为。

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

如何使用Joda-Time检测夏令时是在我的轮班期间开始还是结束?

解决方案如下:

您可以使用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取代,因此,如果您正在考虑进行迁移,则可以开始使用新的Date / Time API,但是如果您使用Joda的代码库很大或不想迁移它现在,您可以考虑其余的答案了。

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

如果您使用的是
Java 8 ,请考虑使用
new java.time API
less bugged and less error-prone than the old APIs更容易。我不确定它是否已适用于所有Android版本(但请参见下面的替代方法)。

如果您使用的是
Java <= 7 ,则可以使用
ThreeTen Backport,它是Java 8的新日期/时间类的很好的反向端口。对于
和Android ,有一种方法可以与
ThreeTenABP一起使用(更多关于
here的用法)。

下面的代码对两者都适用。

唯一的区别是程序包名称(在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是等效的
as the first just internally calls the second。使用
Duration也是等效的,因为它使用它们之间的纳秒级并将其转换为小时。