夏令时持续时间

Posted

技术标签:

【中文标题】夏令时持续时间【英文标题】:Duration with daylight saving 【发布时间】:2017-11-20 22:03:42 【问题描述】:

我有一个对象 Shift,它有两个字段:startDateTimeendDateTime 作为来自 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,betweenuntil是等价的,as the first just internally calls the second。使用Duration 也是等效的,因为它使用它们之间的纳秒并将其转换为小时。

【讨论】:

【参考方案2】:
    您应该使用 TimeZone ID,例如“Europe/London” 将开始和结束时间转换为 GMT 现在查找从 GMT 开始和结束时间的持续时间

当您使用时区 ID 时,会自动处理日光。

【讨论】:

以上是关于夏令时持续时间的主要内容,如果未能解决你的问题,请参考以下文章

请问美国与中国时间时差多少?

计算 DST 转换边界处的持续时间(向前/后退的数量)

计算夏令时和非夏令时之间的时间差

UTC 时间、时区、夏令时和夏令时切换日期

中国有夏令时和冬令时吗?

夏令时时间差距/重叠定义?啥时候为他们“纠正”?