Class AbstractDuration<U extends ChronoUnit>
- All Implemented Interfaces:
TimeSpan<U>
- Direct Known Subclasses:
Duration
Defines a timespan using the default algorithm of Time4J.
Dependent on the sign of the duration there are three cases:
- Empty duration => The method
addTo()
just yields a given time point unaffected. - Positive duration => All contained time units will be added in the order from largest to smallest units. Convertible units will be consolidated in one step. The new time point is relative to given time point argument in the future.
- Negative duration => All contained time units will be subtracted in the reversed order from the smallest to the largest units. Convertible units will be consolidated in one step. The new time point is relative to given time point argument in the past.
Usually possible element overflows will be truncated such that the last valid time point will be determined. The rest of the discussion is about the gregorian calendar system and the addition of months and days, but is also applicable on other calendar systems. Examples in pseudo-code:
- [2011-05-31] + [P4D] = [2011-06-04]
- [2011-05-31] + [P9M] = [2012-02-29]
- [2011-05-31] + [-P1M] = [2011-04-30]
- [2011-05-30] + [P1M1D] = [2011-07-01]
- [2011-05-31] + [P1M1D] = [2011-07-01]
- [2011-07-01] + [-P1M1D] = [2011-05-30]
- [2011-05-31] + [-P1Y1M1D] = [2010-04-30]
If the smallest existing time unit is used then following
invariants hold for the addition of a duration and the delta
between two time points. Let t1 and t2 be two time points with
t1 <= t2
:
- FIRST INVARIANCE:
t1.plus(t1.until(t2)).equals(t2) == true
- SECOND INVARIANCE:
t2.until(t1).equals(t1.until(t2).inverse()) == true
Following condition only holds if either the day-of-month of any involved date is smaller than 28 or if a reversible metric is used:
- THIRD INVARIANCE:
t2.minus(t1.until(t2)).equals(t1) == true
Note: Usually the third invariance is NOT valid. A counter example is given with following dates: {t1, t2} = {[2011-03-31], [2011-07-01]} => P3M1D (using the standard metric) because of [2011-07-01] - P3M1D = [2011-03-30]. Example for using a reversible metric:
PlainDate d1 = PlainDate.of(2011, 3, 31); PlainDate d2 = PlainDate.of(2011, 7, 1); TimeMetric<CalendarUnit, Duration<CalendarUnit>> metric = Duration.inYearsMonthsDays().reversible(); Duration<CalendarUnit> duration = metric.between(d1, d2); // P2M31D Duration<CalendarUnit> invDur = metric.between(d2, d1); // -P2M31D boolean firstInvariance = d1.plus(duration).equals(d2); // true boolean secondInvariance = invDur.equals(duration.inverse()); // true boolean thirdInvariance = d2.minus(duration).equals(d1); // true
About the mathematical background of specified algorithm: Note that the addition is not commutative, hence the order of addition steps will impact the result. For example a two-step-addition looks like:
- [2011-05-30] + [P1M] + [P2D] = [2011-07-02]
- [2011-05-30] + [P2D] + [P1M] = [2011-07-01]
In this context it is understandable that the order of addition steps is dependent on the sign of the duration. If the addition of a negative duration is interpreted as the reversal of the addition of a positive duration then following equivalent relation holds (paying attention to non-commutativity and given the side conditions to compute the duration without remainder completely and to consider a minus-operation as equalizing a plus-operation:
- [t1] - [months] - [days] = [t2]
- => [t1] - [months] - [days] + [days] = [t2] + [days]
- => [t1] - [months] = [t2] + [days]
- => [t1] - [months] + [months] = [t2] + [days] + [months]
- => [t1] = [t2] + [days] + [months] // day-of-month <= 28
The permutation of addition steps is obvious. If Time4J had tried the alternative to first add the months and then the days even in case of a negative duration then we would have with
- t1 = [2013-02-01]
- t2 = [2013-03-31]
- duration = t1.until(t2) = [P1M30D]
the situation that the mentioned third invariance would be violated even if the day of month is the first day of month: t2.minus(P1M30D) would not yield t1 but [2013-01-29]. Surely, the sign-dependent execution of addition steps cannot completely guarantee the third invariance in case of factory-created durations but it can guarantee it at least for all days in original date until the 28th of month.
Furthermore the specified algorithm ensures the second invariance
Duration([t1, t2]) = -Duration([t2, t1])
which expresses
a physical property of any duration as a directed temporal amount.
The second invariance means that the sign of a duration can only
qualify if the first time point is before the second time point or
other way around. The sign must not qualify the always positive length
of a duration itself however.
- Author:
- Meno Hochschild
- See Also:
AbstractMetric
,addTo(TimePoint)
,subtractFrom(TimePoint)
-
Nested Class Summary
Nested classes/interfaces inherited from interface net.time4j.engine.TimeSpan
TimeSpan.Item<U>
-
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptionaddTo(T time)
Adds this duration to given time point using the default algorithm.boolean
Queries if given time unit is part of this time span.long
getPartialAmount(U unit)
Yields the partial amount associated with given time unit.abstract AbstractDuration<U>
inverse()
Creates a copy of this duration with the same amounts and units but the inversed sign.boolean
isEmpty()
Queries if this time span is empty.boolean
Queries if this time span is positive.subtractFrom(T time)
Subtracts this duration from given time point using the default algorithm.toString()
Yields a canonical representation which optionally starts with the sign then continues with the letter "P" followed by a comma-separated sequence of duration items.Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait
Methods inherited from interface net.time4j.engine.TimeSpan
getTotalLength, isNegative
-
Constructor Details
-
AbstractDuration
public AbstractDuration()
-
-
Method Details
-
contains
Description copied from interface:TimeSpan
Queries if given time unit is part of this time span.
By default the implementation uses following expression:
for (Item<?> item : getTotalLength()) { if (item.getUnit().equals(unit)) { return (item.getAmount() > 0); } } return false;
- Specified by:
contains
in interfaceTimeSpan<U extends ChronoUnit>
- Parameters:
unit
- time unit to be asked (optional)- Returns:
true
if exists elsefalse
- See Also:
getPartialAmount(U)
-
getPartialAmount
Description copied from interface:TimeSpan
Yields the partial amount associated with given time unit.
The method returns
0
if this time span does not contain given time unit. In order to get the total length/amount of this time span users have to evaluate the methodTimeSpan.getTotalLength()
instead.- Specified by:
getPartialAmount
in interfaceTimeSpan<U extends ChronoUnit>
- Parameters:
unit
- time unit (optional)- Returns:
- amount as part of time span (
>= 0
)
-
inverse
Creates a copy of this duration with the same amounts and units but the inversed sign.
- Returns:
- inverted duration
-
isPositive
public boolean isPositive()Description copied from interface:TimeSpan
Queries if this time span is positive.
A time span is positive if it is neither empty nor negative.
- Specified by:
isPositive
in interfaceTimeSpan<U extends ChronoUnit>
- Returns:
true
if positive and not empty elsefalse
- See Also:
TimeSpan.isEmpty()
,TimeSpan.isNegative()
-
isEmpty
public boolean isEmpty()Description copied from interface:TimeSpan
Queries if this time span is empty.
Per definition an empty time span has no items with a partial amount different from
0
.- Specified by:
isEmpty
in interfaceTimeSpan<U extends ChronoUnit>
- Returns:
true
if empty elsefalse
-
toString
Yields a canonical representation which optionally starts with the sign then continues with the letter "P" followed by a comma-separated sequence of duration items.
-
addTo
Adds this duration to given time point using the default algorithm.
- Specified by:
addTo
in interfaceTimeSpan<U extends ChronoUnit>
- Type Parameters:
T
- generic type of time point- Parameters:
time
- reference time point to add this time span to- Returns:
- new time point as result of addition
- See Also:
TimeSpan.subtractFrom(TimePoint)
-
subtractFrom
Subtracts this duration from given time point using the default algorithm.
- Specified by:
subtractFrom
in interfaceTimeSpan<U extends ChronoUnit>
- Type Parameters:
T
- generic type of time point- Parameters:
time
- reference time point to subtract this time span from- Returns:
- new time point as result of subtraction
- See Also:
TimeSpan.addTo(TimePoint)
-