夏令时持续时间
Posted
技术标签:
【中文标题】夏令时持续时间【英文标题】:Duration with daylight saving 【发布时间】:2017-11-20 22:03:42 【问题描述】:我有一个对象 Shift
,它有两个字段:startDateTime
和 endDateTime
作为来自 Joda-Time 的 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 日星期日,当地时间 02:00:00。
现在,如果我想跟踪员工的工作小时数
new Duration(startDateTime, endDateTime).toStandardHours().getHours()
会给我 13 个小时。
如何使用 Joda-Time 检测夏令时是在我的轮班时间开始还是结束?
【问题讨论】:
【参考方案1】:您可以使用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
也是等效的,因为它使用它们之间的纳秒并将其转换为小时。
【讨论】:
【参考方案2】:-
您应该使用 TimeZone ID,例如“Europe/London”
将开始和结束时间转换为 GMT
现在查找从 GMT 开始和结束时间的持续时间
当您使用时区 ID 时,会自动处理日光。
【讨论】:
以上是关于夏令时持续时间的主要内容,如果未能解决你的问题,请参考以下文章