【问题标题】: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 检测夏令时是在我的轮班时间开始还是结束?

【问题讨论】:

    标签: java timezone jodatime dst duration


    【解决方案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。根据javadocbetweenuntil是等价的,as the first just internally calls the second。使用Duration 也是等效的,因为它使用它们之间的纳秒并将其转换为小时。

    【讨论】:

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

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

      【讨论】:

        猜你喜欢
        • 2011-10-22
        • 2017-07-11
        • 2012-04-07
        • 2016-02-06
        • 1970-01-01
        • 2015-11-29
        • 2014-03-23
        • 2013-01-31
        • 2012-07-09
        相关资源
        最近更新 更多