Java 以持续时间步长迭代ZoneDateTime间隔

Java 以持续时间步长迭代ZoneDateTime间隔,java,datetime,java-8,java-time,Java,Datetime,Java 8,Java Time,问题 给定一个开始和结束时间戳以及一个持续时间,我希望以持续时间的步长遍历该时间间隔。持续时间应以符号表示。应根据时区考虑夏令时 示例代码: // start/end at switch from summer to winter time ZonedDateTime startTimestamp = ZonedDateTime.of( LocalDateTime.of(2018, 10, 28, 0, 0), ZoneId.of("CET")); ZonedDateTime endTimest

问题

给定一个开始和结束时间戳以及一个持续时间,我希望以持续时间的步长遍历该时间间隔。持续时间应以符号表示。应根据时区考虑夏令时

示例代码:

// 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 parser文档中可以看出,最大持续时间为天):

然后有四个部分,每个部分由一个数字和一个后缀组成。这些部分的后缀是ASCII中的“D”、“H”、“M”和“S”,表示天、小时、分和秒,可以用大写或小写

但该标准规定,持续时间也可以是月或年

持续时间定义一个时间间隔内的干预时间量,以及 由格式P[n]Y[n]M[n]DT[n]H[n]M[n]S或P[n]W表示

问题

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

月份示例:

Start: 01.01.2018
End: 01.01.2019
我希望每个月的第一天都能收到。将
P1M
指定为持续时间当然会引发此异常:

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

尝试使用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
,并在结束时间戳中添加持续时间。

要处理与日期相关的字段(年、月和日),必须使用
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[CET]
2018-03-01T00:00+01:00[CET]
2018-04-01T00:00+02:00[CET]
2018-05-01T00:00+02:00[CET]

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

可供替代的 如果您不介意向应用程序添加依赖项,可以使用三个额外的库:

它包含,封装了
期间
持续时间
,因此“P1M”或“PT1H”都可以工作:

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

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

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

,如果持续时间是非负的,是否可以确保只得到一次迭代?它也不能回答这个问题。问题是“考虑到周、月、年等日历元素,如何正确地在ISO 8601持续时间步骤中通过分区日期时间间隔进行迭代?”(我的重点)