【问题标题】:Iterating through ZonedDateTime interval in Duration steps在 Duration 步骤中迭代 ZonedDateTime 间隔
【发布时间】:2018-04-20 06:34:23
【问题描述】:

问题

给定一个开始和结束时间戳以及一个持续时间,我想以持续时间为步长迭代该时间间隔。持续时间应以ISO 8601 表示法指定。应根据时区考虑夏令时。

示例代码:

// start/end at switch from summer to winter time
ZonedDateTime startTimestamp = ZonedDateTime.of( LocalDateTime.of(2018, 10, 28, 0, 0), ZoneId.of("CET"));
ZonedDateTime endTimestamp = startTimestamp.plusHours(5);

Duration duration = Duration.parse( "PT1H");
while( startTimestamp.isBefore(endTimestamp)) {
    System.out.println( startTimestamp);
    startTimestamp = startTimestamp.plus( duration);
}

结果:

2018-10-28T00:00+02:00[CET]
2018-10-28T01:00+02:00[CET]
2018-10-28T02:00+02:00[CET]
2018-10-28T02:00+01:00[CET]
2018-10-28T03:00+01:00[CET]

问题在于,只要持续时间最长为天,它就可以工作。来自 Duration 解析器文档:

然后有四个部分,每个部分由一个数字和一个后缀组成。这些部分具有“D”、“H”、“M”和“S”的 ASCII 后缀,表示天、小时、分钟和秒,接受大小写。

ISO 8601 标准指定持续时间也可能以月和年为单位。

持续时间定义了时间间隔中的干预时间量,并且 由格式 P[n]Y[n]M[n]DT[n]H[n]M[n]S 或 P[n]W

表示

问题

考虑到周、月、年的日历元素,您如何在 ISO 8601 持续时间步骤中正确迭代 ZonedDateTime 间隔?

月份示例:

Start: 01.01.2018
End: 01.01.2019

我想每个月的第一天。将P1M 指定为持续时间当然会引发此异常:

Exception in thread "main" java.time.format.DateTimeParseException: 
Text cannot be parsed to a Duration

【问题讨论】:

    标签: java datetime java-8 java-time


    【解决方案1】:

    要使用与日期相关的字段(年、月和日),您必须使用 java.time.Period。示例:

    ZonedDateTime startTimestamp = ZonedDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneId.of("CET"));
    ZonedDateTime endTimestamp = startTimestamp.plusMonths(5);
    
    Period period = Period.parse("P1M");
    while (startTimestamp.isBefore(endTimestamp)) {
        System.out.println(startTimestamp);
        startTimestamp = startTimestamp.plus(period);
    }
    

    打印出来:

    2018-01-01T00:00+01:00[CET]
    2018-02-01T00:00+01:00[中欧时间]
    2018-03-01T00:00+01:00[CET]
    2018-04-01T00:00+02:00[中欧时间]
    2018-05-01T00:00+02:00[CET]

    不幸的是,java.time 已将 ISO8601 持续时间分为 2 类,其中Period 适用于基于日期的字段,而Duration 适用于基于时间的字段。

    另类

    如果您不介意向应用程序添加依赖项,可以使用三个额外的库:http://www.threeten.org/threeten-extra/

    它包含class PeriodDuration,封装了PeriodDuration,因此“P1M”或“PT1H”都可以工作:

    // this works
    PeriodDuration period = PeriodDuration.parse("P1M");
    
    // this too
    PeriodDuration period = PeriodDuration.parse("PT1H");
    

    plus方法可以接收PeriodDuration,因为它也实现了TemporalAmount

    【讨论】:

      【解决方案2】:

      尝试使用 do while 循环。

      ZonedDateTime startTimestamp = ZonedDateTime.of(LocalDateTime.of(2018, 4, 20, 12, 10), ZoneId.of("CET"));
      ZonedDateTime endTimestamp = startTimestamp.plusHours(5);
      
      Duration duration = Duration.parse("PT1H");
      do {
          System.out.println(startTimestamp.toLocalTime());
          startTimestamp = endTimestamp.plus(duration);
      } while (startTimestamp.isBefore(endTimestamp));
      

      您必须重新初始化startTimeStamp,并在结束时间戳中添加持续时间。

      【讨论】:

      • 如果持续时间为非负数,那不能确保您只获得一次迭代吗?它也没有回答这个问题。问题是“考虑到 周、月、年 的日历元素,您如何在 ISO 8601 持续时间步骤中正确迭代 ZonedDateTime 间隔?” (我的重点)
      猜你喜欢
      • 2011-08-18
      • 2017-08-30
      • 2017-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-05
      • 2018-05-24
      • 2018-01-12
      相关资源
      最近更新 更多