Skip to content

Commit 8e77c69

Browse files
committed
support for intervals surrounding instants
see issue #672
1 parent 6db6b4f commit 8e77c69

File tree

2 files changed

+106
-12
lines changed

2 files changed

+106
-12
lines changed

range/src/main/java/net/time4j/range/MomentInterval.java

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import net.time4j.format.expert.IsoDecimalStyle;
4646
import net.time4j.format.expert.ParseLog;
4747
import net.time4j.format.expert.SignPolicy;
48+
import net.time4j.scale.TimeScale;
4849
import net.time4j.tz.TZID;
4950
import net.time4j.tz.Timezone;
5051
import net.time4j.tz.ZonalOffset;
@@ -327,7 +328,7 @@ public static MomentInterval until(Instant end) {
327328
* @param alignment determines how to align the interval around moment (in range {@code 0.0 <= x <= 1.0})
328329
* @return new moment interval
329330
* @throws IllegalArgumentException if the duration is negative or the alignment is not finite or out of range
330-
* @throws UnsupportedOperationException if any given or calculated moment is before 1972
331+
* @throws UnsupportedOperationException if any given or calculated moment is before 1972 (only for SI-duration)
331332
* @see #LEFT_ALIGNED
332333
* @see #CENTERED
333334
* @see #RIGHT_ALIGNED
@@ -348,26 +349,66 @@ public static MomentInterval until(Instant end) {
348349
* @param alignment determines how to align the interval around moment (in range {@code 0.0 <= x <= 1.0})
349350
* @return new moment interval
350351
* @throws IllegalArgumentException if the duration is negative or the alignment is not finite or out of range
351-
* @throws UnsupportedOperationException if any given or calculated moment is before 1972
352+
* @throws UnsupportedOperationException if any given or calculated moment is before 1972 (only for SI-duration)
352353
* @see #LEFT_ALIGNED
353354
* @see #CENTERED
354355
* @see #RIGHT_ALIGNED
355356
* @since 3.34/4.29
356357
*/
357358
public static MomentInterval surrounding(
358359
Moment moment,
359-
MachineTime<SI> duration,
360+
MachineTime<?> duration,
360361
double alignment
361362
) {
362363

363-
if (alignment == 1.0) { // avoid possible rounding errors
364-
return MomentInterval.between(moment.minus(duration), moment);
365-
} else if ((Double.compare(alignment, 0.0) < 0) || (Double.compare(alignment, 1.0) > 0)) {
364+
if ((Double.compare(alignment, 0.0) < 0) || (Double.compare(alignment, 1.0) > 0)) {
366365
throw new IllegalArgumentException("Out of range: " + alignment);
367366
}
368367

369-
Moment start = moment.minus(duration.multipliedBy(alignment));
370-
return MomentInterval.between(start, start.plus(duration));
368+
Moment start = subtract(moment, duration.multipliedBy(alignment));
369+
return MomentInterval.between(start, (alignment == 1.0) ? moment : add(start, duration));
370+
371+
}
372+
373+
/**
374+
* <p>Creates an interval surrounding given instant. </p>
375+
*
376+
* <p>Equivalent to {@link #surrounding(Moment, MachineTime, double)
377+
* surrounding(Moment.from(instant), duration, alignment)}. </p>
378+
*
379+
* @param instant embedded instant at focus of alignment
380+
* @param duration machine time duration
381+
* @param alignment determines how to align the interval around instant (in range {@code 0.0 <= x <= 1.0})
382+
* @return new moment interval
383+
* @throws IllegalArgumentException if the duration is negative or the alignment is not finite or out of range
384+
* @see #LEFT_ALIGNED
385+
* @see #CENTERED
386+
* @see #RIGHT_ALIGNED
387+
* @since 3.34/4.29
388+
*/
389+
/*[deutsch]
390+
* <p>Erzeugt ein Intervall, das den angegebenen Zeitpunkt umgibt. </p>
391+
*
392+
* <p>&Auml;quivalent zu {@link #surrounding(Moment, MachineTime, double)
393+
* surrounding(Moment.from(instant), duration, alignment)}. </p>
394+
*
395+
* @param instant embedded instant at focus of alignment
396+
* @param duration machine time duration
397+
* @param alignment determines how to align the interval around instant (in range {@code 0.0 <= x <= 1.0})
398+
* @return new moment interval
399+
* @throws IllegalArgumentException if the duration is negative or the alignment is not finite or out of range
400+
* @see #LEFT_ALIGNED
401+
* @see #CENTERED
402+
* @see #RIGHT_ALIGNED
403+
* @since 3.34/4.29
404+
*/
405+
public static MomentInterval surrounding(
406+
Instant instant,
407+
MachineTime<TimeUnit> duration,
408+
double alignment
409+
) {
410+
411+
return MomentInterval.surrounding(Moment.from(instant), duration, alignment);
371412

372413
}
373414

@@ -1499,6 +1540,38 @@ private static boolean hasSecondOffset(
14991540

15001541
}
15011542

1543+
@SuppressWarnings("unchecked")
1544+
private static Moment add(
1545+
Moment moment,
1546+
MachineTime<?> duration
1547+
) {
1548+
1549+
if (duration.getScale() == TimeScale.UTC) {
1550+
MachineTime<SI> mt = (MachineTime<SI>) duration;
1551+
return moment.plus(mt);
1552+
} else {
1553+
MachineTime<TimeUnit> mt = (MachineTime<TimeUnit>) duration;
1554+
return moment.plus(mt);
1555+
}
1556+
1557+
}
1558+
1559+
@SuppressWarnings("unchecked")
1560+
private static Moment subtract(
1561+
Moment moment,
1562+
MachineTime<?> duration
1563+
) {
1564+
1565+
if (duration.getScale() == TimeScale.UTC) {
1566+
MachineTime<SI> mt = (MachineTime<SI>) duration;
1567+
return moment.minus(mt);
1568+
} else {
1569+
MachineTime<TimeUnit> mt = (MachineTime<TimeUnit>) duration;
1570+
return moment.minus(mt);
1571+
}
1572+
1573+
}
1574+
15021575
/**
15031576
* @serialData Uses
15041577
* <a href="../../../serialized-form.html#net.time4j.range.SPX">

range/src/test/java/net/time4j/range/BasicMomentRangeTest.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,21 +309,42 @@ public void move() {
309309
}
310310

311311
@Test
312-
public void surroundingInterval() {
312+
public void surroundingIntervalSI() {
313313
Moment moment = PlainTimestamp.of(2017, 9, 9, 10, 0).atUTC();
314-
MachineTime<SI> duration = MachineTime.ofSIUnits(3600, 0);
314+
MachineTime<SI> duration = MachineTime.ofSIUnits(5400, 0);
315315

316316
MomentInterval centered = MomentInterval.surrounding(moment, duration, MomentInterval.CENTERED);
317+
Moment startCentered = PlainTimestamp.of(2017, 9, 9, 9, 15).atUTC();
318+
Moment endCentered = PlainTimestamp.of(2017, 9, 9, 10, 45).atUTC();
319+
assertThat(centered, is(MomentInterval.between(startCentered, endCentered)));
320+
321+
MomentInterval left = MomentInterval.surrounding(moment, duration, MomentInterval.LEFT_ALIGNED);
322+
Moment startLeft = PlainTimestamp.of(2017, 9, 9, 8, 30).atUTC();
323+
Moment endLeft = PlainTimestamp.of(2017, 9, 9, 10, 0).atUTC();
324+
assertThat(left, is(MomentInterval.between(startLeft, endLeft)));
325+
326+
MomentInterval right = MomentInterval.surrounding(moment, duration, MomentInterval.RIGHT_ALIGNED);
327+
Moment startRight = PlainTimestamp.of(2017, 9, 9, 10, 0).atUTC();
328+
Moment endRight = PlainTimestamp.of(2017, 9, 9, 11, 30).atUTC();
329+
assertThat(right, is(MomentInterval.between(startRight, endRight)));
330+
}
331+
332+
@Test
333+
public void surroundingIntervalPOSIX() {
334+
Instant instant = PlainTimestamp.of(2017, 9, 9, 10, 0).atUTC().toTemporalAccessor();
335+
MachineTime<TimeUnit> duration = MachineTime.ofPosixUnits(3600, 0);
336+
337+
MomentInterval centered = MomentInterval.surrounding(instant, duration, MomentInterval.CENTERED);
317338
Moment startCentered = PlainTimestamp.of(2017, 9, 9, 9, 30).atUTC();
318339
Moment endCentered = PlainTimestamp.of(2017, 9, 9, 10, 30).atUTC();
319340
assertThat(centered, is(MomentInterval.between(startCentered, endCentered)));
320341

321-
MomentInterval left = MomentInterval.surrounding(moment, duration, MomentInterval.LEFT_ALIGNED);
342+
MomentInterval left = MomentInterval.surrounding(instant, duration, MomentInterval.LEFT_ALIGNED);
322343
Moment startLeft = PlainTimestamp.of(2017, 9, 9, 9, 0).atUTC();
323344
Moment endLeft = PlainTimestamp.of(2017, 9, 9, 10, 0).atUTC();
324345
assertThat(left, is(MomentInterval.between(startLeft, endLeft)));
325346

326-
MomentInterval right = MomentInterval.surrounding(moment, duration, MomentInterval.RIGHT_ALIGNED);
347+
MomentInterval right = MomentInterval.surrounding(instant, duration, MomentInterval.RIGHT_ALIGNED);
327348
Moment startRight = PlainTimestamp.of(2017, 9, 9, 10, 0).atUTC();
328349
Moment endRight = PlainTimestamp.of(2017, 9, 9, 11, 0).atUTC();
329350
assertThat(right, is(MomentInterval.between(startRight, endRight)));

0 commit comments

Comments
 (0)