[#585] Add support for DATE, TIME and INTERVAL arithmetic
This commit is contained in:
parent
f917e72193
commit
bba467bcee
@ -44,6 +44,8 @@ import static junit.framework.Assert.fail;
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
import static org.jooq.impl.Factory.cast;
|
||||
import static org.jooq.impl.Factory.castNull;
|
||||
import static org.jooq.impl.Factory.dateDiff;
|
||||
import static org.jooq.impl.Factory.timestampDiff;
|
||||
import static org.jooq.impl.Factory.val;
|
||||
import static org.jooq.tools.unsigned.Unsigned.ubyte;
|
||||
import static org.jooq.tools.unsigned.Unsigned.uint;
|
||||
@ -1191,6 +1193,8 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
public void testDateTime() throws Exception {
|
||||
|
||||
// [#1009] SQL DATE doesn't have a time zone. SQL TIMESTAMP does
|
||||
long tsShift = -3600000;
|
||||
|
||||
Record record =
|
||||
create().select(
|
||||
val(new Date(0)).as("d"),
|
||||
@ -1202,7 +1206,7 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
|
||||
// ... (except for SQLite)
|
||||
if (getDialect() != SQLITE)
|
||||
assertEquals(new Date(-3600000), record.getValue("d"));
|
||||
assertEquals(new Date(tsShift), record.getValue("d"));
|
||||
|
||||
assertEquals(new Time(0), record.getValue("t"));
|
||||
assertEquals(new Timestamp(0), record.getValue("ts"));
|
||||
@ -1211,8 +1215,8 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
|
||||
// TODO: Add tests for reading date / time / interval types into pojos
|
||||
|
||||
// [#566] INTERVAL arithmetic
|
||||
// --------------------------
|
||||
// [#566] INTERVAL arithmetic: multiplication
|
||||
// ------------------------------------------
|
||||
record =
|
||||
create().select(
|
||||
val(new YearToMonth(1)).div(2).as("y1"),
|
||||
@ -1231,5 +1235,82 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
assertEquals(new DayToSecond(0, 12), record.getValue("d1"));
|
||||
assertEquals(new DayToSecond(2), record.getValue("d2"));
|
||||
assertEquals(new DayToSecond(1), record.getValue("d3"));
|
||||
|
||||
// [#566] INTERVAL arithmetic: addition
|
||||
// ------------------------------------
|
||||
record =
|
||||
create().select(
|
||||
val(new Date(0)).add(1).as("d1"),
|
||||
val(new Date(0)).sub(1).as("d2"),
|
||||
val(new Date(0)).add(new YearToMonth(1, 6)).as("d3"),
|
||||
val(new Date(0)).sub(new YearToMonth(1, 6)).as("d4"),
|
||||
val(new Date(0)).add(new DayToSecond(2)).as("d5"),
|
||||
val(new Date(0)).sub(new DayToSecond(2)).as("d6"),
|
||||
|
||||
val(new Timestamp(0)).add(1).as("ts1"),
|
||||
val(new Timestamp(0)).sub(1).as("ts2"),
|
||||
val(new Timestamp(0)).add(new YearToMonth(1, 6)).as("ts3"),
|
||||
val(new Timestamp(0)).sub(new YearToMonth(1, 6)).as("ts4"),
|
||||
val(new Timestamp(0)).add(new DayToSecond(2)).as("ts5"),
|
||||
val(new Timestamp(0)).sub(new DayToSecond(2)).as("ts6")
|
||||
).fetchOne();
|
||||
|
||||
Calendar cal;
|
||||
|
||||
cal = cal();
|
||||
cal.add(Calendar.DATE, 1);
|
||||
assertEquals(new Date(cal.getTimeInMillis()), record.getValue("d1"));
|
||||
assertEquals(new Timestamp(cal.getTimeInMillis() - tsShift), record.getValue("ts1"));
|
||||
|
||||
cal = cal();
|
||||
cal.add(Calendar.DATE, -1);
|
||||
assertEquals(new Date(cal.getTimeInMillis()), record.getValue("d2"));
|
||||
assertEquals(new Timestamp(cal.getTimeInMillis() - tsShift), record.getValue("ts2"));
|
||||
|
||||
cal = cal();
|
||||
cal.add(Calendar.MONTH, 18);
|
||||
assertEquals(new Date(cal.getTimeInMillis()), record.getValue("d3"));
|
||||
assertEquals(new Timestamp(cal.getTimeInMillis() - tsShift), record.getValue("ts3"));
|
||||
|
||||
cal = cal();
|
||||
cal.add(Calendar.MONTH, -18);
|
||||
assertEquals(new Date(cal.getTimeInMillis()), record.getValue("d4"));
|
||||
assertEquals(new Timestamp(cal.getTimeInMillis() - tsShift), record.getValue("ts4"));
|
||||
|
||||
cal = cal();
|
||||
cal.add(Calendar.DATE, 2);
|
||||
assertEquals(new Date(cal.getTimeInMillis()), record.getValue("d5"));
|
||||
assertEquals(new Timestamp(cal.getTimeInMillis() - tsShift), record.getValue("ts5"));
|
||||
|
||||
cal = cal();
|
||||
cal.add(Calendar.DATE, -2);
|
||||
assertEquals(new Date(cal.getTimeInMillis()), record.getValue("d6"));
|
||||
assertEquals(new Timestamp(cal.getTimeInMillis() - tsShift), record.getValue("ts6"));
|
||||
|
||||
// [#566] INTERVAL arithmetic: difference
|
||||
// --------------------------------------
|
||||
record =
|
||||
create().select(
|
||||
dateDiff(new Date(0), new Date(24 * 60 * 60 * 1000L)).as("d1"),
|
||||
dateDiff(new Date(24 * 60 * 60 * 1000L), new Date(0)).as("d2"),
|
||||
//TODO [#566] Make this work!
|
||||
//timeDiff(new Time(0), new Time(60 * 60 * 1000L)).as("t1"),
|
||||
//timeDiff(new Time(60 * 60 * 1000L), new Time(0)).as("t2"),
|
||||
timestampDiff(new Timestamp(0), new Timestamp(24 * 60 * 60 * 1000L)).as("ts1"),
|
||||
timestampDiff(new Timestamp(24 * 60 * 60 * 1000L), new Timestamp(0)).as("ts2")
|
||||
).fetchOne();
|
||||
|
||||
assertEquals(-1, record.getValue("d1"));
|
||||
assertEquals(1, record.getValue("d2"));
|
||||
//assertEquals(new DayToSecond(0, 1).neg(), record.getValue("t1"));
|
||||
//assertEquals(new DayToSecond(0, 1), record.getValue("t2"));
|
||||
assertEquals(new DayToSecond(1).neg(), record.getValue("ts1"));
|
||||
assertEquals(new DayToSecond(1), record.getValue("ts2"));
|
||||
}
|
||||
|
||||
private Calendar cal() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTimeInMillis(-3600000);
|
||||
return cal;
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,6 +54,7 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.impl.Factory;
|
||||
import org.jooq.types.Interval;
|
||||
|
||||
/**
|
||||
* A field used in tables and conditions
|
||||
@ -291,60 +292,161 @@ public interface Field<T> extends NamedTypeProviderQueryPart<T>, AliasProvider<F
|
||||
|
||||
/**
|
||||
* An arithmetic expression adding this to value.
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>If this is a numeric field, then the value is added arithmetically</li>
|
||||
* <li>If this is a date time field, then [value] days are added to this date</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #add(Field)
|
||||
*/
|
||||
@Support
|
||||
Field<T> add(Number value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression adding this to value
|
||||
* An arithmetic expression adding an interval to this.
|
||||
*
|
||||
* @see #add(Field)
|
||||
*/
|
||||
@Support
|
||||
Field<T> add(Field<? extends Number> value);
|
||||
Field<T> add(Interval<?> value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression to add value to this.
|
||||
* <p>
|
||||
* The behaviour of this operation is as follows:
|
||||
* <table border="1">
|
||||
* <tr>
|
||||
* <th>Operand 1</th>
|
||||
* <th>Operand 2</th>
|
||||
* <th>Result Type</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Numeric</td>
|
||||
* <td>Numeric</td>
|
||||
* <td>Numeric</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Date / Time</td>
|
||||
* <td>Numeric</td>
|
||||
* <td>Date / Time</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Date / Time</td>
|
||||
* <td>Interval</td>
|
||||
* <td>Date / Time</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interval</td>
|
||||
* <td>Interval</td>
|
||||
* <td>Interval</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
@Support
|
||||
Field<T> add(Field<?> value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression subtracting value from this.
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>If this is a numeric field, then the value is subtracted
|
||||
* arithmetically</li>
|
||||
* <li>If this is a date time field, then [value] days are subtracted to
|
||||
* this date</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #sub(Field)
|
||||
*/
|
||||
@Support
|
||||
Field<T> sub(Number value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression subtracting value from this
|
||||
* An arithmetic expression subtracting an interval from this.
|
||||
*
|
||||
* @see #sub(Field)
|
||||
*/
|
||||
@Support
|
||||
Field<T> sub(Field<? extends Number> value);
|
||||
Field<T> sub(Interval<?> value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression subtracting value from this.
|
||||
* <p>
|
||||
* <table border="1">
|
||||
* <tr>
|
||||
* <th>Operand 1</th>
|
||||
* <th>Operand 2</th>
|
||||
* <th>Result Type</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Numeric</td>
|
||||
* <td>Numeric</td>
|
||||
* <td>Numeric</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Date / Time</td>
|
||||
* <td>Numeric</td>
|
||||
* <td>Date / Time</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Date / Time</td>
|
||||
* <td>Interval</td>
|
||||
* <td>Date / Time</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interval</td>
|
||||
* <td>Interval</td>
|
||||
* <td>Interval</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* In order to subtract one date time field from another, use any of these
|
||||
* methods:
|
||||
* <ul>
|
||||
* <li> {@link Factory#dateDiff(Field, Field)}</li>
|
||||
* <li> {@link Factory#timeDiff(Field, Field)}</li>
|
||||
* <li> {@link Factory#timestampDiff(Field, Field)}</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Support
|
||||
Field<T> sub(Field<?> value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression multiplying this with value
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>If this is a numeric field, then the result is a number of the same
|
||||
* type as this field.</li>
|
||||
* <li>If this is an <code>INTERVAL</code> field, then the result is also an
|
||||
* <code>INTERVAL</code> field (see {@link Interval})</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Support
|
||||
Field<T> mul(Number value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression multiplying this with value
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>If this is a numeric field, then the result is a number of the same
|
||||
* type as this field.</li>
|
||||
* <li>If this is an <code>INTERVAL</code> field, then the result is also an
|
||||
* <code>INTERVAL</code> field (see {@link Interval})</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Support
|
||||
Field<T> mul(Field<? extends Number> value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression dividing this by value
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>If this is a numeric field, then the result is a number of the same
|
||||
* type as this field.</li>
|
||||
* <li>If this is an <code>INTERVAL</code> field, then the result is also an
|
||||
* <code>INTERVAL</code> field (see {@link Interval})</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Support
|
||||
Field<T> div(Number value);
|
||||
|
||||
/**
|
||||
* An arithmetic expression dividing this by value
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>If this is a numeric field, then the result is a number of the same
|
||||
* type as this field.</li>
|
||||
* <li>If this is an <code>INTERVAL</code> field, then the result is also an
|
||||
* <code>INTERVAL</code> field (see {@link Interval})</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Support
|
||||
Field<T> div(Field<? extends Number> value);
|
||||
|
||||
@ -71,6 +71,7 @@ import org.jooq.SortOrder;
|
||||
import org.jooq.WindowIgnoreNullsStep;
|
||||
import org.jooq.WindowPartitionByStep;
|
||||
import org.jooq.tools.Convert;
|
||||
import org.jooq.types.Interval;
|
||||
|
||||
abstract class AbstractField<T> extends AbstractNamedTypeProviderQueryPart<T> implements Field<T> {
|
||||
|
||||
@ -225,12 +226,17 @@ abstract class AbstractField<T> extends AbstractNamedTypeProviderQueryPart<T> im
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> add(Interval<?> value) {
|
||||
return add(val(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* This default implementation is known to be overridden by
|
||||
* {@link Expression} to generate neater expressions
|
||||
*/
|
||||
@Override
|
||||
public Field<T> add(Field<? extends Number> value) {
|
||||
public Field<T> add(Field<?> value) {
|
||||
return new Expression<T>(ADD, this, nullSafe(value));
|
||||
}
|
||||
|
||||
@ -249,7 +255,12 @@ abstract class AbstractField<T> extends AbstractNamedTypeProviderQueryPart<T> im
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> sub(Field<? extends Number> value) {
|
||||
public final Field<T> sub(Interval<?> value) {
|
||||
return sub(val(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> sub(Field<?> value) {
|
||||
return new Expression<T>(SUBTRACT, this, nullSafe(value));
|
||||
}
|
||||
|
||||
|
||||
@ -136,7 +136,7 @@ public abstract class CustomField<T> extends AbstractField<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> add(Field<? extends Number> value) {
|
||||
public final Field<T> add(Field<?> value) {
|
||||
return super.add(value);
|
||||
}
|
||||
|
||||
|
||||
@ -92,7 +92,7 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> add(Field<? extends Number> value) {
|
||||
public final Field<T> add(Field<?> value) {
|
||||
if (operator == ExpressionOperator.ADD) {
|
||||
rhs.add(value);
|
||||
return this;
|
||||
|
||||
@ -131,6 +131,7 @@ import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.InvalidResultException;
|
||||
import org.jooq.exception.SQLDialectNotSupportedException;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.types.DayToSecond;
|
||||
|
||||
/**
|
||||
* A factory providing implementations to the org.jooq interfaces
|
||||
@ -4450,7 +4451,7 @@ public class Factory implements FactoryOperations {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Pseudo fields and date time functions
|
||||
// XXX date time functions
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@ -4483,6 +4484,165 @@ public class Factory implements FactoryOperations {
|
||||
return new CurrentTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date difference in number of days
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<Integer> dateDiff(Date date1, Date date2) {
|
||||
return dateDiff(val(date1), val(date2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date difference in number of days
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<Integer> dateDiff(Field<Date> date1, Date date2) {
|
||||
return dateDiff(nullSafe(date1), val(date2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date difference in number of days
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<Integer> dateDiff(Date date1, Field<Date> date2) {
|
||||
return dateDiff(val(date1), nullSafe(date2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date difference in number of days
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<Integer> dateDiff(Field<Date> date1, Field<Date> date2) {
|
||||
// TODO [#585] This cast shouldn't be necessary
|
||||
return nullSafe(date1).sub(nullSafe(date2)).cast(Integer.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timestampDiff(Timestamp timestamp1, Timestamp timestamp2) {
|
||||
return timestampDiff(val(timestamp1), val(timestamp2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timestampDiff(Field<Timestamp> timestamp1, Timestamp timestamp2) {
|
||||
return timestampDiff(nullSafe(timestamp1), val(timestamp2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timestampDiff(Timestamp timestamp1, Field<Timestamp> timestamp2) {
|
||||
return timestampDiff(val(timestamp1), nullSafe(timestamp2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timestampDiff(Field<Timestamp> timestamp1, Field<Timestamp> timestamp2) {
|
||||
// TODO [#585] This cast shouldn't be necessary
|
||||
return nullSafe(timestamp1).sub(nullSafe(timestamp2)).cast(DayToSecond.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timeDiff(Time time1, Time time2) {
|
||||
return timeDiff(val(time1), val(time2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timeDiff(Field<Time> time1, Time time2) {
|
||||
return timeDiff(nullSafe(time1), val(time2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timeDiff(Time time1, Field<Time> time2) {
|
||||
return timeDiff(val(time1), nullSafe(time2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp difference as a <code>INTERVAL DAY TO SECOND</code>
|
||||
* type
|
||||
* <p>
|
||||
* This translates into any dialect
|
||||
*
|
||||
* @see Field#sub(Field)
|
||||
*/
|
||||
@Support
|
||||
public static Field<DayToSecond> timeDiff(Field<Time> time1, Field<Time> time2) {
|
||||
// TODO [#585] This cast shouldn't be necessary
|
||||
return nullSafe(time1).sub(nullSafe(time2)).cast(DayToSecond.class);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX other functions
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the current_user() function
|
||||
* <p>
|
||||
|
||||
@ -133,6 +133,20 @@ public final class DayToSecond implements Interval<DayToSecond> {
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Inteval API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final DayToSecond neg() {
|
||||
return new DayToSecond(days, hours, minutes, seconds, nano, !negative);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DayToSecond abs() {
|
||||
return new DayToSecond(days, hours, minutes, seconds, nano, false);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Comparable and Object API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -101,4 +101,13 @@ import java.io.Serializable;
|
||||
*/
|
||||
public interface Interval<T extends Interval<T>> extends Serializable, Comparable<T> {
|
||||
|
||||
/**
|
||||
* Negate the interval (change its sign)
|
||||
*/
|
||||
T neg();
|
||||
|
||||
/**
|
||||
* Get the absolute value of the interval (set its sign to positive)
|
||||
*/
|
||||
T abs();
|
||||
}
|
||||
|
||||
@ -101,6 +101,20 @@ public final class YearToMonth implements Interval<YearToMonth> {
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Inteval API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final YearToMonth neg() {
|
||||
return new YearToMonth(years, months, !negative);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final YearToMonth abs() {
|
||||
return new YearToMonth(years, months, false);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Comparable and Object API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user