4545import net .time4j .format .expert .IsoDecimalStyle ;
4646import net .time4j .format .expert .ParseLog ;
4747import net .time4j .format .expert .SignPolicy ;
48+ import net .time4j .scale .TimeScale ;
4849import net .time4j .tz .TZID ;
4950import net .time4j .tz .Timezone ;
5051import 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>Ä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">
0 commit comments