在 Duration 步骤中迭代 ZonedDateTime 间隔
Iterating through ZonedDateTime interval in Duration steps
问题
给定开始和结束时间戳以及持续时间,我想按持续时间的步长迭代该时间间隔。持续时间应以 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 解析器文档:
There are then four sections, each consisting of a number and a suffix. The sections have suffixes in ASCII of "D", "H", "M" and "S" for days, hours, minutes and seconds, accepted in upper or lower case.
但是 ISO 8601 标准指定持续时间也可能以月和年为单位。
Durations define the amount of intervening time in a time interval and
are represented by the format P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W
问题
考虑周、月、年的日历元素,您如何通过 ZonedDateTime 间隔在 ISO 8601 持续时间步骤中正确迭代?
月份示例:
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 持续时间分为 2 类,其中 Period
适用于基于日期的字段,而 Duration
适用于基于时间的字段。
备选
如果您不介意向您的应用程序添加依赖项,您可以使用三个额外的库:http://www.threeten.org/threeten-extra/
它包含封装了 Period
和 Duration
的 class PeriodDuration
,因此 "P1M" 或 "PT1H" 都可以工作:
// this works
PeriodDuration period = PeriodDuration.parse("P1M");
// this too
PeriodDuration period = PeriodDuration.parse("PT1H");
而plus
方法可以接收一个PeriodDuration
,因为它也实现了TemporalAmount
.
问题
给定开始和结束时间戳以及持续时间,我想按持续时间的步长迭代该时间间隔。持续时间应以 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 解析器文档:
There are then four sections, each consisting of a number and a suffix. The sections have suffixes in ASCII of "D", "H", "M" and "S" for days, hours, minutes and seconds, accepted in upper or lower case.
但是 ISO 8601 标准指定持续时间也可能以月和年为单位。
Durations define the amount of intervening time in a time interval and are represented by the format P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W
问题
考虑周、月、年的日历元素,您如何通过 ZonedDateTime 间隔在 ISO 8601 持续时间步骤中正确迭代?
月份示例:
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 持续时间分为 2 类,其中 Period
适用于基于日期的字段,而 Duration
适用于基于时间的字段。
备选
如果您不介意向您的应用程序添加依赖项,您可以使用三个额外的库:http://www.threeten.org/threeten-extra/
它包含封装了 Period
和 Duration
的 class PeriodDuration
,因此 "P1M" 或 "PT1H" 都可以工作:
// this works
PeriodDuration period = PeriodDuration.parse("P1M");
// this too
PeriodDuration period = PeriodDuration.parse("PT1H");
而plus
方法可以接收一个PeriodDuration
,因为它也实现了TemporalAmount
.