Skip to content

Commit

Permalink
reversible time metric
Browse files Browse the repository at this point in the history
  • Loading branch information
MenoData committed Nov 4, 2019
1 parent bb203c9 commit 5ce066c
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 107 deletions.
25 changes: 15 additions & 10 deletions time4j-android/src/main/java/net/time4j/Duration.java
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ public static Duration<ClockUnit> ofClockUnits(
*
* @param <U> generic unit type
* @param units time units to be used in calculation
* @return immutable metric for calculating a duration in given units
* @return reversible immutable metric for calculating a duration in given units
* @throws IllegalArgumentException if no time unit is given or
* if there are unit duplicates
*/
Expand Down Expand Up @@ -604,7 +604,7 @@ public static Duration<ClockUnit> ofClockUnits(
*
* @param <U> generic unit type
* @param units time units to be used in calculation
* @return immutable metric for calculating a duration in given units
* @return reversible immutable metric for calculating a duration in given units
* @throws IllegalArgumentException if no time unit is given or
* if there are unit duplicates
*/
Expand All @@ -620,7 +620,7 @@ public static <U extends IsoUnit> TimeMetric<U, Duration<U>> in(U... units) {
* <p>Finally the resulting duration will be normalized such that
* smaller units will be converted to bigger units if possible. </p>
*
* @return immutable metric for calculating a duration in years,
* @return reversible immutable metric for calculating a duration in years,
* months and days
* @see #in(IsoUnit[]) in(U[])
* @see CalendarUnit#YEARS
Expand All @@ -634,7 +634,7 @@ public static <U extends IsoUnit> TimeMetric<U, Duration<U>> in(U... units) {
* Zeiteinheiten so weit wie m&ouml;glich in gro&szlig;e Einheiten
* umgerechnet. </p>
*
* @return immutable metric for calculating a duration in years,
* @return reversible immutable metric for calculating a duration in years,
* months and days
* @see #in(IsoUnit[]) in(U[])
* @see CalendarUnit#YEARS
Expand All @@ -653,7 +653,7 @@ public static TimeMetric<CalendarUnit, Duration<CalendarUnit>> inYearsMonthsDays
* <p>Finally the resulting duration will be normalized such that
* smaller units will be converted to bigger units if possible. </p>
*
* @return immutable metric for calculating a duration in clock units
* @return reversible immutable metric for calculating a duration in clock units
* @see #in(IsoUnit[]) in(U[])
* @see ClockUnit#HOURS
* @see ClockUnit#MINUTES
Expand All @@ -667,7 +667,7 @@ public static TimeMetric<CalendarUnit, Duration<CalendarUnit>> inYearsMonthsDays
* Zeiteinheiten so weit wie m&ouml;glich in gro&szlig;e Einheiten
* umgerechnet. </p>
*
* @return immutable metric for calculating a duration in clock units
* @return reversible immutable metric for calculating a duration in clock units
* @see #in(IsoUnit[]) in(U[])
* @see ClockUnit#HOURS
* @see ClockUnit#MINUTES
Expand All @@ -686,7 +686,7 @@ public static TimeMetric<ClockUnit, Duration<ClockUnit>> inClockUnits() {
* <p>Finally the resulting duration will be normalized such that
* smaller units will be converted to bigger units if possible. </p>
*
* @return immutable metric for calculating a duration in week-based years, weeks and days
* @return reversible immutable metric for calculating a duration in week-based years, weeks and days
* @see #in(IsoUnit[]) in(U[])
* @see CalendarUnit#weekBasedYears()
* @see CalendarUnit#WEEKS
Expand All @@ -699,7 +699,7 @@ public static TimeMetric<ClockUnit, Duration<ClockUnit>> inClockUnits() {
* <p>Am Ende wird die Darstellung automatisch normalisiert, also kleine
* Zeiteinheiten so weit wie m&ouml;glich in gro&szlig;e Einheiten umgerechnet. </p>
*
* @return immutable metric for calculating a duration in week-based years, weeks and days
* @return reversible immutable metric for calculating a duration in week-based years, weeks and days
* @see #in(IsoUnit[]) in(U[])
* @see CalendarUnit#weekBasedYears()
* @see CalendarUnit#WEEKS
Expand Down Expand Up @@ -730,7 +730,7 @@ public static TimeMetric<IsoDateUnit, Duration<IsoDateUnit>> inWeekBasedUnits()
*
* @param tz timezone
* @param units time units to be used in calculation
* @return zonal metric for calculating a duration in given units
* @return non-reversible zonal metric for calculating a duration in given units
* @throws IllegalArgumentException if no time unit is given or
* if there are unit duplicates
* @since 1.2
Expand All @@ -755,7 +755,7 @@ public static TimeMetric<IsoDateUnit, Duration<IsoDateUnit>> inWeekBasedUnits()
*
* @param tz timezone
* @param units time units to be used in calculation
* @return zonal metric for calculating a duration in given units
* @return non-reversible zonal metric for calculating a duration in given units
* @throws IllegalArgumentException if no time unit is given or
* if there are unit duplicates
* @since 1.2
Expand Down Expand Up @@ -4072,6 +4072,11 @@ Duration<IsoUnit> between(

}

@Override
public TimeMetric<IsoUnit, Duration<IsoUnit>> reversible() {
throw new UnsupportedOperationException("Not reversible.");
}

private int getOffset(ChronoEntity<?> entity) {

return this.tz.getStrategy().getOffset(
Expand Down
17 changes: 11 additions & 6 deletions time4j-android/src/main/java/net/time4j/MachineTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,34 +101,34 @@ public final class MachineTime<U>
new MachineTime<SI>(0, 0, UTC);

/**
* Metric on the POSIX scale (without leap seconds).
* Reversible metric on the POSIX scale (without leap seconds).
*
* @since 2.0
*/
/*[deutsch]
* Metrik auf der POSIX-Skala (ohne Schaltsekunden).
* Umkehrbare Metrik auf der POSIX-Skala (ohne Schaltsekunden).
*
* @since 2.0
*/
public static final TimeMetric<TimeUnit, MachineTime<TimeUnit>> ON_POSIX_SCALE =
new Metric<TimeUnit>(POSIX);
new Metric<TimeUnit>(POSIX);

/**
* <p>Metric on the UTC scale (inclusive leap seconds). </p>
* <p>Reversible metric on the UTC scale (inclusive leap seconds). </p>
*
* <p>Time points before 1972 are not supported. </p>
*
* @since 2.0
*/
/*[deutsch]
* <p>Metrik auf der UTC-Skala (inklusive Schaltsekunden). </p>
* <p>Umkehrbare Metrik auf der UTC-Skala (inklusive Schaltsekunden). </p>
*
* <p>Zeitpunkte vor 1972 werden nicht unterst&uuml;tzt. </p>
*
* @since 2.0
*/
public static final TimeMetric<TimeUnit, MachineTime<SI>> ON_UTC_SCALE =
new Metric<SI>(UTC);
new Metric<SI>(UTC);

private static final long serialVersionUID = -4150291820807606229L;

Expand Down Expand Up @@ -1737,6 +1737,11 @@ <T extends TimePoint<? super TimeUnit, T>> MachineTime<U> between(

}

@Override
public TimeMetric<TimeUnit, MachineTime<U>> reversible() {
return this;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
* given time point argument in the future. </li>
* <li>Negative duration =&gt; 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
* units. Convertible units will be consolidated in one step. The
* new time point is relative to given time point argument in the
* past. </li>
* </ol>
Expand Down Expand Up @@ -71,15 +71,33 @@
* {@code t2.until(t1).equals(t1.until(t2).inverse()) == true}
* </li></ul>
*
* <p><strong>Note:</strong> The THIRD INVARIANCE
* {@code t1.plus(t1.until(t2)).minus(t1.until(t2)).equals(t1) == true}
* is often INVALID. A counter example where this invariance is
* violated is given with following dates:
* {t1, t2} = {[2011-05-31], [2011-07-01]}. But if the additional
* condition is required that the day of month is never after 28th
* of a month then this third invariance can be guaranteed.
* Therefore it is recommended to avoid dates near the end of
* month in addition. </p>
* <p>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: </p>
*
* <ul><li>THIRD INVARIANCE:
* {@code t2.minus(t1.until(t2)).equals(t1) == true}
* </li></ul>
*
* <p><strong>Note:</strong> Usually the third invariance is NOT valid. A counter example
* is given with following dates: {t1, t2} = {[2011-03-31], [2011-07-01]} =&gt; P3M1D (using
* the standard metric) because of [2011-07-01] - P3M1D = [2011-03-30]. Example for using
* a reversible metric: </p>
*
* <pre>
* PlainDate d1 = PlainDate.of(2011, 3, 31);
* PlainDate d2 = PlainDate.of(2011, 7, 1);
*
* TimeMetric&lt;CalendarUnit, Duration&lt;CalendarUnit&gt;&gt; metric =
* Duration.inYearsMonthsDays().reversible();
* Duration&lt;CalendarUnit&gt; duration =
* metric.between(d1, d2); // P2M31D
* Duration&lt;CalendarUnit&gt; 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
* </pre>
*
* <div style="background-color:#E0E0E0;padding:5px;margin:5px;">
*
Expand All @@ -100,7 +118,7 @@
* 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 (with t1-day-of-month &lt;= 28): </p>
* equalizing a plus-operation: </p>
*
* <ul>
* <li>[t1] - [months] - [days] = [t2]</li>
Expand All @@ -124,15 +142,16 @@
* 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 but it can guarantee it at least for all days in original
* date until the 28th of month. </p>
* 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. </p>
*
* <p>Furthermore the specified algorithm ensures the second invariance
* {@code Duration([t1, t2]) = -Duration([t2, t1])} which expresses
* a physical property of any duration. 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. </p>
* 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. </p>
* </div>
*
* @author Meno Hochschild
Expand Down Expand Up @@ -191,14 +210,34 @@
* {@code t2.until(t1).equals(t1.until(t2).inverse()) == true}
* </li></ul>
*
* <p><strong>Zu beachten:</strong> Allgemein gilt die DRITTE INVARIANZ
* {@code t1.plus(t1.until(t2)).minus(t1.until(t2)).equals(t1) == true}
* NICHT. Ein Gegenbeispiel ist mit {t1, t2} = {[2011-05-31], [2011-07-01]}
* gegeben. Wird aber hier als zus&auml;tzliche Randbedingung verlangt,
* da&szlig; etwa der Tag des Monats nicht nach dem 28. liegt, dann gilt
* diese Invarianz doch noch. Es wid daher empfohlen, bei der Addition von
* Monaten m&ouml;glichst Datumsangaben zu vermeiden, die am Ende eines
* Monats liegen. </p>
* <p>Die folgende Invarianzbedingung gilt nur, wenn entweder der betroffene
* Tag des Monats in den beteiligten Datumsangaben kleiner als 28 ist oder
* wenn eine umkehrbare Metrik verwendet wird: </p>
*
* <ul><li>DRITTE INVARIANZ:
* {@code t2.minus(t1.until(t2)).equals(t1) == true}
* </li></ul>
*
* <p><strong>Note:</strong> Gew&ouml;hnlich ist die dritte Invarianzbedingung nicht g&uuml;ltig.
* Ein Gegenbeispiel ist mit folgenden Werten gegeben: {t1, t2} = {[2011-03-31], [2011-07-01]}
* =&gt; P3M1D (im Fall der Standardmetrik) wegen [2011-07-01] - P3M1D = [2011-03-30]. Beispiel
* zur Verwendung einer umkehrbaren Metrik: </p>
*
* <pre>
* PlainDate d1 = PlainDate.of(2011, 3, 31);
* PlainDate d2 = PlainDate.of(2011, 7, 1);
*
* TimeMetric&lt;CalendarUnit, Duration&lt;CalendarUnit&gt;&gt; metric =
* Duration.inYearsMonthsDays().reversible();
* Duration&lt;CalendarUnit&gt; duration =
* metric.between(d1, d2); // P2M31D
* Duration&lt;CalendarUnit&gt; 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
* </pre>
*
* <div style="background-color:#E0E0E0;padding:5px;margin:5px;">
*
Expand Down Expand Up @@ -240,8 +279,9 @@
* Tag des Monats im Ausgangsdatum der erste ist. Denn: t2.minus(P1M30D)
* erg&auml;be dann nicht t1, sondern [2013-01-29]. Zwar kann die
* vorzeichenabh&auml;ngige Ausf&uuml;hrung der Rechenschritte nicht
* vollst&auml;ndig die dritte Invarianz garantieren, aber wenigstens
* doch f&uuml;r alle Tage im Ausgangsdatum bis zum 28. eines Monats. </p>
* vollst&auml;ndig die dritte Invarianz garantieren (im Fall von nicht
* berechneten Dauer-Objekten), aber wenigstens doch f&uuml;r alle Tage
* im Ausgangsdatum bis zum 28. eines Monats. </p>
*
* <p>Gleichzeitig hilft der Time4J-Algorithmus die Invarianz
* {@code Duration([t1, t2]) = -Duration([t2, t1])} einzuhalten,
Expand Down
Loading

0 comments on commit 5ce066c

Please sign in to comment.